--- /dev/null
+//---------------------------- swappable_vector.h ---------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 1999, 2000 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------- swappable_vector.h ---------------------------
+#ifndef __deal2__swappable_vector_h
+#define __deal2__swappable_vector_h
+
+
+#include <lac/vector.h>
+
+#ifdef DEAL_II_USE_MT
+# include <base/thread_management.h>
+#endif
+
+#include <string>
+
+
+
+/**
+ * This class is a wrapper to the #Vector# class which allows to swap
+ * out the data to a file and reload it later on. It handles the
+ * management of the name of the file where the data is to be stored
+ * temporarily and removes the file is necessary at the end of the
+ * lifetime of the vector.
+ *
+ * There are functions to swap the data to a file, and to reload
+ * it. There is also a function #alert# that can be used to signal to
+ * an object of this class that the data will be needed shortly, so
+ * the object can initiate that the data be loaded already. While in
+ * non-multithreading mode, this function has no effect since #reload#
+ * has to be called afterwards anyway. On the other hand, in
+ * multithreading mode, the data is preloaded in the background using
+ * a thread on its own, and may already be available at the time when
+ * #reload# is called. If it is not available, #reload# waits until
+ * the detached thread has loaded the data.
+ *
+ * @author Wolfgang Bangerth, 1999, 2000
+ */
+template <typename number>
+class SwappableVector : public Vector<number>
+{
+ public:
+ /**
+ * Constructor. Does nothing
+ * apart from calling the
+ * constructor of the underlying
+ * class.
+ */
+ SwappableVector ();
+
+ /**
+ * Copy constructor. Copies the
+ * data if #v# contains some, but
+ * does not do so if #v# is empty
+ * or has its data swapped
+ * out. In the latter case, warn
+ * about that. In particular do
+ * not take over ownership of any
+ * files that #v# might own (as,
+ * for example, #C++#'s
+ * #auto_ptr# objects would do).
+ */
+ SwappableVector (const SwappableVector &v);
+
+ /**
+ * Destructor. If this class
+ * still owns a file to which
+ * temporary data was stored,
+ * then it is deleted.
+ */
+ virtual ~SwappableVector ();
+
+ /**
+ * Copy operator. Do mostly the
+ * same as the copy constructor
+ * does; if necessary, delete
+ * temporary files owned by this
+ * object at first.
+ */
+ SwappableVector & operator = (const SwappableVector &);
+
+ /**
+ * Swap out the data of this
+ * vector to the file of which
+ * the name is given. It is
+ * assumed that the file can be
+ * overwritten if it exists, and
+ * ownership of this file is
+ * assumed by this object. The
+ * file is deleted either upon
+ * calling #kill_file#, or on
+ * destruction of this object.
+ *
+ * The content of the vector is
+ * cleared and it size is reset
+ * to zero.
+ *
+ * If this object owns another
+ * file, for example when
+ * #swap_out# but no #kill_file#
+ * has previously been called,
+ * then that is deleted first.
+ */
+ void swap_out (const string &filename);
+
+ /**
+ * Reload the data of this vector
+ * from the file to which it has
+ * been stored previously using
+ * #swap_out#. Since the file is
+ * not deleted after reloading,
+ * you can call #reload# multiple
+ * times, in between you may do
+ * everything with the vector,
+ * including changing its size.
+ *
+ * This function resets the size
+ * of the vector to the number of
+ * elements there were upon
+ * calling #swap_out# before.
+ */
+ void reload ();
+
+ /**
+ * Calling this function can be
+ * used to alert this vector that
+ * it will need to reload its
+ * data soon. It has no effect if
+ * the data of the vector is
+ * already present, and it has no
+ * effect in single-thread mode
+ * as well, but in multithread
+ * mode, it spawns another thread
+ * that reads the data in
+ * parallel to the usual
+ * execution of the program, such
+ * that when #reload# is called,
+ * the data may eventually be
+ * available already. It might
+ * therefore be wirthwhile to
+ * call this function some time
+ * in advance, if you know that
+ * the data will be needed, and
+ * loading takes some time, for
+ * instance if the file to which
+ * the data was written is not in
+ * a local tmp directory.
+ *
+ * Calling this function multiple
+ * times before calling #reload#
+ * is allowed and has no effect
+ * for subsequent calls. Calling
+ * this function while the data
+ * is still or already in memory
+ * is allowed and has no effect.
+ */
+ void alert ();
+
+
+ /**
+ * Remove the file to which the
+ * data has been stored the last
+ * time. After this, the object
+ * does not own any file any
+ * more, so of course you can't
+ * call #reload# no more.
+ *
+ * If this object does not own a
+ * file, for example since
+ * #swap_out# was not called, or
+ * because #kill_file# has been
+ * called previously, then this
+ * function does nothing.
+ */
+ void kill_file ();
+
+ /**
+ * Return the name of the file to
+ * which the data was stored the
+ * last time you called
+ * #swap_out#. If #swap_out# was
+ * not called, or if in between
+ * #kill_file# was called, then
+ * the filename is an empty
+ * string.
+ */
+ const string & get_filename () const;
+
+ /**
+ * Exception.
+ */
+ DeclException0 (ExcSizeZero);
+ /**
+ * Exception.
+ */
+ DeclException0 (ExcSizeNonzero);
+ /**
+ * Exception.
+ */
+ DeclException1 (ExcInvalidFilename,
+ string,
+ << "The filename <" << arg1
+ << "> is not a valid one here.");
+ /**
+ * Exception.
+ */
+ DeclException0 (ExcInvalidCopyOperation);
+
+ private:
+ /**
+ * Name of the file to which data
+ * was swapped out. If no data is
+ * presently swapped out
+ * (i.e. before calling
+ * #swap_out# and after
+ * #kill_file#), the string is
+ * empty, indicating no ownership
+ * of files.
+ */
+ string filename;
+
+#ifdef DEAL_II_USE_MT
+ /**
+ * If in multithread mode, then
+ * the #alert# function has
+ * functionality, but needs to
+ * coordinate with the #reload#
+ * function. This is done through
+ * the following lock.
+ */
+ ACE_Thread_Mutex lock;
+
+ /**
+ * Declare a thread manager that
+ * is used to spawn threads in
+ * #alert# detached.
+ */
+ static ACE_Thread_Manager thread_manager;
+#endif
+
+ /**
+ * Flag by which the #alert#
+ * function signifies that the
+ * data has been preloaded
+ * already. This flag is always
+ * #false# in non-MT mode.
+ */
+ bool data_is_preloaded;
+
+ /**
+ * Internal function that
+ * actually reloads the
+ * vector. Called from #reload#
+ * and #alert#.
+ *
+ * The parameter specifies
+ * whether the function shall set
+ * #data_is_preloaded# or
+ * not. The calling functions
+ * can't sometimes do this
+ * themselves, since they call
+ * this function detached, so
+ * this function has to signal
+ * success itself if this is
+ * required.
+ */
+ void reload_vector (const bool set_flag);
+};
+
+
+
+/*---------------------------- swappable_vector.h ---------------------------*/
+/* end of #ifndef __deal2__swappable_vector_h */
+#endif
+/*---------------------------- swappable_vector.h ---------------------------*/
--- /dev/null
+//---------------------------- swappable_vector.templates.h ---------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 1999, 2000 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------- swappable_vector.templates.h ---------------------------
+#ifndef __deal2__swappable_vector_templates_h
+#define __deal2__swappable_vector_templates_h
+
+
+#include <lac/swappable_vector.h>
+#include <fstream>
+#include <iostream>
+
+
+
+#ifdef DEAL_II_USE_MT
+ // allocate static variable
+template <typename number>
+ACE_Thread_Manager SwappableVector<number>::thread_manager;
+#endif
+
+
+
+
+template <typename number>
+SwappableVector<number>::SwappableVector ()
+ :
+ data_is_preloaded (false)
+{};
+
+
+
+template <typename number>
+SwappableVector<number>::SwappableVector (const SwappableVector<number> &v) :
+ Vector<number>(v),
+ filename (),
+ data_is_preloaded (false)
+{
+ Assert (v.filename == "", ExcInvalidCopyOperation());
+};
+
+
+
+template <typename number>
+SwappableVector<number>::~SwappableVector ()
+{
+ // if the vector was stored in a
+ // file previously, and that has
+ // not been deleted in the
+ // meantime, then we kill that file
+ // first, before killing the vector
+ // itself
+
+ if (filename != "")
+ kill_file ();
+};
+
+
+
+template <typename number>
+SwappableVector<number> &
+SwappableVector<number>::operator= (const SwappableVector<number> &v)
+{
+ // if necessary, first delete data
+ if (filename != "")
+ kill_file ();
+
+ // if in MT mode, block all other
+ // operations
+#ifdef DEAL_II_USE_MT
+ lock.acquire ();
+#endif
+
+ Vector<number>::operator = (v);
+ data_is_preloaded = false;
+
+#ifdef DEAL_II_USE_MT
+ lock.release ();
+#endif
+
+
+ return *this;
+};
+
+
+
+template <typename number>
+void SwappableVector<number>::swap_out (const string &name)
+{
+ // if the vector was stored in
+ // another file previously, and
+ // that has not been deleted in the
+ // meantime, then we kill that file
+ // first
+ if (filename != "")
+ kill_file ();
+
+ filename = name;
+
+ Assert (size() != 0, ExcSizeZero());
+
+ // if in MT mode, block all other
+ // operations
+#ifdef DEAL_II_USE_MT
+ lock.acquire ();
+#endif
+
+ // check that we have not called
+ // #alert# without the respective
+ // #reload# function
+ Assert (data_is_preloaded == false, ExcInternalError());
+
+ ofstream tmp_out(filename.c_str());
+ block_write (tmp_out);
+ tmp_out.close ();
+
+ reinit (0);
+
+#ifdef DEAL_II_USE_MT
+ lock.release ();
+#endif
+};
+
+
+
+template <typename number>
+void SwappableVector<number>::reload ()
+{
+ // if in MT mode: synchronise with
+ // possibly existing #alert# calls
+#ifdef DEAL_II_USE_MT
+ lock.acquire ();
+#endif
+ // if data was already preloaded,
+ // then there is no more need to
+ // load it
+ if (data_is_preloaded == false)
+ // reload data. note that this
+ // function also releases the
+ // lock
+ reload_vector (false);
+ else
+ {
+ // clear flag since no more
+ // needed
+ data_is_preloaded = false;
+
+ // release lock. the lock is
+ // also released in the other
+ // branch of the if-clause
+#ifdef DEAL_II_USE_MT
+ lock.release ();
+#endif
+ };
+};
+
+
+
+template <typename number>
+void SwappableVector<number>::alert ()
+{
+ // note: this function does nothing
+ // in non-MT mode
+#ifdef DEAL_II_USE_MT
+
+ // synchronise with possible other
+ // invokations of this function and
+ // other functions in this class
+ lock.acquire ();
+
+ // calling this function multiple
+ // times does no harm:
+ if ( (data_is_preloaded == true) ||
+ // calling this function while the
+ // vector is active does no harm
+ // either
+ (size() != 0))
+ lock.release ();
+ else
+ // data has not been preloaded so
+ // far, so go on!
+ Threads::spawn (thread_manager,
+ Threads::encapsulate (&SwappableVector<number>::reload_vector)
+ .collect_args(this, true));
+ // note that reload_vector also
+ // releases the lock
+#endif
+};
+
+
+
+template <typename number>
+void SwappableVector<number>::reload_vector (const bool set_flag)
+{
+ Assert (filename != "", ExcInvalidFilename (filename));
+ Assert (size() == 0, ExcSizeNonzero());
+
+ ifstream tmp_in(filename.c_str());
+ block_read (tmp_in);
+ tmp_in.close ();
+
+ // release the lock that was
+ // acquired by the calling
+ // functions
+#ifdef DEAL_II_USE_MT
+ // set the flag if so required
+ if (set_flag)
+ data_is_preloaded = true;
+ lock.release ();
+#endif
+};
+
+
+
+template <typename number>
+void SwappableVector<number>::kill_file ()
+{
+ // if in MT mode, wait for other
+ // operations to finish first
+ // (there should be none, but who
+ // knows)
+#ifdef DEAL_II_USE_MT
+ lock.acquire();
+#endif
+
+ Assert (data_is_preloaded == false, ExcInternalError());
+
+ if (filename != "")
+ {
+ int status = remove (filename.c_str());
+ AssertThrow (status == 0, ExcInternalError());
+
+ filename = "";
+ };
+
+#ifdef DEAL_II_USE_MT
+ lock.release ();
+#endif
+};
+
+
+
+template <typename number>
+const string &
+SwappableVector<number>::get_filename () const
+{
+ return filename;
+};
+
+
+
+
+#endif // __deal2__swappable_vector_templates_h