<commit_before>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_FORMAT_MACROS

#include "monarch/data/json/JsonWriter.h"
#include "monarch/io/ByteArrayInputStream.h"
#include "monarch/io/File.h"
#include "monarch/io/FileInputStream.h"
#include "monarch/io/FileOutputStream.h"
#include "monarch/io/FileList.h"
#include "monarch/io/InputStream.h"
#include "monarch/logging/Logging.h"
#include "monarch/modest/Kernel.h"
#include "monarch/net/TcpSocket.h"
#include "monarch/net/Url.h"
#include "monarch/http/CookieJar.h"
#include "monarch/http/HttpHeader.h"
#include "monarch/http/HttpRequest.h"
#include "monarch/http/HttpResponse.h"
#include "monarch/http/HttpConnectionServicer.h"
#include "monarch/http/HttpRequestServicer.h"
#include "monarch/http/HttpClient.h"
#include "monarch/net/Server.h"
#include "monarch/net/NullSocketDataPresenter.h"
#include "monarch/net/SslSocketDataPresenter.h"
#include "monarch/net/SocketDataPresenterList.h"
#include "monarch/net/Url.h"
#include "monarch/rt/Atomic.h"
#include "monarch/rt/ExclusiveLock.h"
#include "monarch/rt/System.h"
#include "monarch/rt/DynamicObject.h"
#include "monarch/rt/DynamicObjectIterator.h"
#include "monarch/test/Test.h"
#include "monarch/test/TestModule.h"
#include "monarch/util/Date.h"
#include "monarch/util/StringTools.h"

using namespace std;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::test;
using namespace monarch::util;

namespace mo_test_pong
{

/**
 * PingPong Test
 *
 * Invoke with the following:
 *
 *   ./monarch-run pong
 *
 * See configs/apps/pong.config.in for option defaults. Use standard monarch
 * "--json-option key=value" option to adjust options.
 *
 *    pong.chunked=<bool>: use chunked encoding
 *    pong.dynoStats=<bool>: return DynamicObject stats with regular stats
 *    pong.num=<int32>: number of connections to service
 *    pong.port=<int32>: port to serve on
 *    pong.ssl=<bool>: use SSL
 *    pong.time=<int32>: milliseconds to run the test
 *    pong.threadStackSize=<int32>: set stack size
 *    pong.threads=<int32>: set number of threads
 *    pong.maxConnections=<int32>: set max number of connections
 *    pong.backlog=<int32>: set connection backlog queue size
 *
 * Endpoints:
 *    /: return "204 No Content"
 *    /pong: return "Pong!"
 *    /data[/size]: return a specified number of bytes of content. default=0.
 *    /stats: return JSON object with various
 *
 */

// stats and control
class PingPong
{
private:
   uint64_t mStart;
   uint64_t mLast;
   uint64_t mServiced;
   uint64_t mNum;
   ExclusiveLock mLock;
   Config mConfig;

public:
   PingPong(Config cfg) :
      mStart(0),
      mLast(0),
      mServiced(0),
      mConfig(cfg)
   {
      mNum = cfg["num"]->getUInt64();
   }

   virtual ~PingPong() {}

   virtual void start()
   {
      mStart = System::getCurrentMilliseconds();
      mLast = mStart;
   }

   virtual void quit()
   {
      mLock.notifyAll();
   }

   virtual Config& getConfig()
   {
      return mConfig;
   }

   virtual ExclusiveLock& getLock()
   {
      return mLock;
   }

   virtual void service()
   {
      // set last serviced time for effective ping service time
      // avoids counting time between ping and stats calls
      mLast = System::getCurrentMilliseconds();

      // This is a bit sloppy and may do the lock notify multiple times and
      // increase mServiced more than mNum.  Assumption is that this doesn't
      // matter for this sort of performance testing.
      uint64_t s = Atomic::incrementAndFetch(&mServiced);
      if(mNum != 0 && s >= mNum)
      {
         quit();
      }
   }

   virtual DynamicObject getStats()
   {
      uint64_t tms = mLast - mStart;
      double rate = (tms == 0) ?
         0.0 :
         (double)mServiced * 1000.0 / (double)tms;

      DynamicObject stats;
      stats["serviced"] = mServiced;
      stats["num"] = mNum;
      stats["elapsed ms"] = tms;
      stats["req/s"] = rate;

      /*
      printf("Serviced: %" PRIu64 "/%" PRIu64 " in %0.3gs (%g r/s)\n",
         mServiced, mNum, (double)t, rate);
      if(mConfig["dynoStats"]->getBoolean())
      {
         JsonWriter::writeToStdOut(DynamicObjectImpl::getStats());
      }
      */

      return stats;
   }
};

class NoContentServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   NoContentServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~NoContentServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      mPingPong->service();
   }
};

class PingServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;
   const char* mContent;
   bool mChunked;

public:
   PingServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
      mChunked = pingPong->getConfig()["chunked"]->getBoolean();
   }

   virtual ~PingServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      const char* str = "Pong!";
      int len = 5;

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mChunked)
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "text/plain");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(str, len);
      response->sendBody(&bais, NULL);
      mPingPong->service();
   }
};

class ConstByteInputStream : public InputStream
{
protected:
   int mLength;
   char mData[4096];

public:
   ConstByteInputStream(char b, int length) :
      mLength(length)
   {
      memset(mData, b, min(mLength, 4096));
   }

   int read(char* b, int length)
   {
      // max is 4k or remaining, let higher levels loop
      int max = min(mLength, 4096);
      // return max or length
      int rval = min(max, length);
      // reduce remaining
      mLength -= rval;
      memcpy(b, mData, rval);
      return rval;
   }
};

class DataServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;
   string mPath;
   bool mChunked;

public:
   DataServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong),
      mPath(path)
   {
      mChunked = pingPong->getConfig()["chunked"]->getBoolean();
      if(mPath.length() > 0 && mPath[mPath.length()] != '/')
      {
         mPath.push_back('/');
      }
   }

   virtual ~DataServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      // get length param from value after root path, else 0
      const char* path = request->getHeader()->getPath();
      Url url(path);
      DynamicObject tokens;
      url.getTokenizedPath(tokens, mPath.c_str());
      int len = 0;
      if(tokens->length() > 0)
      {
         len = tokens[0]->getInt32();
      }

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mChunked)
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "text/plain");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      // send const bytes of a specified length
      ConstByteInputStream cbis('.', len);
      response->sendBody(&cbis, NULL);
      mPingPong->service();
   }
};

class StatsServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   StatsServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~StatsServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      Config& c = mPingPong->getConfig();
      // generate stats string
      DynamicObject stats;
      if(c["dynoStats"]->getBoolean())
      {
         stats["dyno"] = DynamicObjectImpl::getStats();
      }
      stats["ping"] = mPingPong->getStats();
      string statsstr = JsonWriter::writeToString(stats);
      int len = statsstr.length();

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mPingPong->getConfig()["chunked"]->getBoolean())
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "application/json");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(statsstr.c_str(), len);
      response->sendBody(&bais, NULL);
   }
};

class QuitServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   QuitServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~QuitServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      mPingPong->quit();
   }
};

static void runPingTest(TestRunner& tr)
{
   tr.test("Ping");

   Config cfg = tr.getApp()->getConfig()["pong"];

   // Stats and control
   PingPong pingPong(cfg);

   // create kernel
   Kernel k;

   // set thread stack size in engine (128k)
   k.getEngine()->getThreadPool()->setThreadStackSize(
      cfg["threadStackSize"]->getUInt32());

   // optional for testing --
   // limit threads to 2: one for accepting, 1 for handling
   //k.getEngine()->getThreadPool()->setPoolSize(2);
   k.getEngine()->getThreadPool()->setPoolSize(cfg["threads"]->getUInt32());

   // start engine
   k.getEngine()->start();

   // create server
   Server server;
   server.setMaxConnectionCount(cfg["maxConnections"]->getInt32());
   InternetAddress address("0.0.0.0", cfg["port"]->getUInt32());

   // create SSL/generic http connection servicer
   HttpConnectionServicer hcs;
//   SslContext context;
//   SslSocketDataPresenter presenter1(&context);
//   NullSocketDataPresenter presenter2;
//   SocketDataPresenterList list(false);
//   list.add(&presenter1);
//   list.add(&presenter2);
   //server.addConnectionService(&address, &hcs);//, &list);
   server.addConnectionService(
      &address, &hcs, NULL, "pong",
      cfg["maxConnections"]->getInt32(),
      cfg["backlog"]->getInt32());

   // create test http request servicer
   NoContentServicer noContentSrv(&pingPong, "/");
   hcs.addRequestServicer(&noContentSrv, false);

   PingServicer ping(&pingPong, "/pong");
   hcs.addRequestServicer(&ping, false);

   DataServicer data(&pingPong, "/data");
   hcs.addRequestServicer(&data, false);

   StatsServicer stats(&pingPong, "/stats");
   hcs.addRequestServicer(&stats, false);

   QuitServicer quit(&pingPong, "/quit");
   hcs.addRequestServicer(&quit, false);

   if(server.start(&k))
   {
      uint64_t num = cfg["num"]->getUInt64();
      MO_INFO("Server started.");
      if(num == 0)
      {
         MO_INFO("Servicing forever. CTRL-C to quit.");
      }
      {
         MO_INFO("Servicing approximately %" PRIu64 " connections.", num);
      }
   }
   else if(Exception::get() != NULL)
   {
      MO_ERROR("Server started with errors=%s\n",
         Exception::get()->getMessage());
   }

   // start timing
   pingPong.start();

   // either serve for limited time, or wait for lock
   uint32_t time = cfg["time"]->getUInt32();
   if(time != 0)
   {
      Thread::sleep(time);
   }
   else
   {
      pingPong.getLock().wait();
   }

   server.stop();
   MO_INFO("Server stopped.");

   // stop kernel engine
   k.getEngine()->stop();

   tr.passIfNoException();
}

static bool run(TestRunner& tr)
{
   if(tr.isTestEnabled("pong"))
   {
      runPingTest(tr);
   }
   return true;
}

} // end namespace

MO_TEST_MODULE_FN("monarch.tests.pong.test", "1.0", mo_test_pong::run)
<commit_msg>Pong benchmark test updates and optimizations.<commit_after>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_FORMAT_MACROS

#include "monarch/data/json/JsonWriter.h"
#include "monarch/io/ByteArrayInputStream.h"
#include "monarch/io/File.h"
#include "monarch/io/FileInputStream.h"
#include "monarch/io/FileOutputStream.h"
#include "monarch/io/FileList.h"
#include "monarch/io/InputStream.h"
#include "monarch/logging/Logging.h"
#include "monarch/modest/Kernel.h"
#include "monarch/net/TcpSocket.h"
#include "monarch/net/Url.h"
#include "monarch/http/CookieJar.h"
#include "monarch/http/HttpHeader.h"
#include "monarch/http/HttpRequest.h"
#include "monarch/http/HttpResponse.h"
#include "monarch/http/HttpConnectionServicer.h"
#include "monarch/http/HttpRequestServicer.h"
#include "monarch/http/HttpClient.h"
#include "monarch/net/Server.h"
#include "monarch/net/NullSocketDataPresenter.h"
#include "monarch/net/SslSocketDataPresenter.h"
#include "monarch/net/SocketDataPresenterList.h"
#include "monarch/net/Url.h"
#include "monarch/rt/Atomic.h"
#include "monarch/rt/ExclusiveLock.h"
#include "monarch/rt/System.h"
#include "monarch/rt/DynamicObject.h"
#include "monarch/rt/DynamicObjectIterator.h"
#include "monarch/test/Test.h"
#include "monarch/test/TestModule.h"
#include "monarch/util/Date.h"
#include "monarch/util/StringTools.h"

using namespace std;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::test;
using namespace monarch::util;

namespace mo_test_pong
{

/**
 * PingPong Test
 *
 * Invoke with the following:
 *
 *   ./monarch-run pong
 *
 * See configs/apps/pong.config.in for option defaults. Use standard monarch
 * "--json-option key=value" option to adjust options.
 *
 *    pong.chunked=<bool>: use chunked encoding
 *    pong.dynoStats=<bool>: return DynamicObject stats with regular stats
 *    pong.num=<int32>: number of connections to service
 *    pong.port=<int32>: port to serve on
 *    pong.ssl=<bool>: use SSL
 *    pong.time=<int32>: milliseconds to run the test
 *    pong.threadStackSize=<int32>: set stack size
 *    pong.threads=<int32>: set number of threads
 *    pong.maxConnections=<int32>: set max number of connections
 *    pong.backlog=<int32>: set connection backlog queue size
 *
 * Endpoints:
 *    /: return "204 No Content"
 *    /pong: return "Pong!"
 *    /data[/size]: return a specified number of bytes of content. default=0.
 *    /stats: return JSON object with various
 *    /reset: reset the server stats
 *    /quit: quit the server
 */

// stats and control
class PingPong
{
private:
   uint64_t mStart;
   uint64_t mLast;
   uint64_t mServiced;
   uint64_t mNum;
   uint64_t mContentBytes;
   ExclusiveLock mLock;
   Config mConfig;

public:
   PingPong(Config cfg) :
      mConfig(cfg)
   {
      mNum = mConfig["num"]->getUInt64();
      reset();
   }

   virtual ~PingPong() {}

   virtual void reset()
   {
      mStart = System::getCurrentMilliseconds();
      mLast = mStart;
      mServiced = 0;
      mContentBytes = 0;
   }

   virtual void quit()
   {
      mLock.notifyAll();
   }

   virtual Config& getConfig()
   {
      return mConfig;
   }

   virtual ExclusiveLock& getLock()
   {
      return mLock;
   }

   virtual void service(uint64_t bytes = 0)
   {
      // set last serviced time for effective ping service time
      // avoids counting time between ping and stats calls
      mLast = System::getCurrentMilliseconds();

      if(bytes > 0)
      {
         //Atomic::addAndFetch(&mContentBytes, bytes);
         //__sync_add_and_fetch(&mContentBytes, bytes);
         mContentBytes += bytes;
      }

      // This is a bit sloppy and may do the lock notify multiple times and
      // increase mServiced more than mNum.  Assumption is that this doesn't
      // matter for this sort of performance testing.
      uint64_t s = Atomic::incrementAndFetch(&mServiced);
      if(mNum != 0 && s >= mNum)
      {
         quit();
      }
   }

   virtual DynamicObject getStats()
   {
      uint64_t tms = mLast - mStart;
      double rate = (tms == 0) ?
         0.0 :
         (double)mServiced * 1000.0 / (double)tms;

      DynamicObject stats;
      stats["serviced"] = mServiced;
      stats["contentBytes"] = mContentBytes;
      stats["num"] = mNum;
      stats["elapsed ms"] = tms;
      stats["req/s"] = rate;

      /*
      printf("Serviced: %" PRIu64 "/%" PRIu64 " in %0.3gs (%g r/s)\n",
         mServiced, mNum, (double)t, rate);
      if(mConfig["dynoStats"]->getBoolean())
      {
         JsonWriter::writeToStdOut(DynamicObjectImpl::getStats());
      }
      */

      return stats;
   }
};

class NoContentServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   NoContentServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~NoContentServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      mPingPong->service();
   }
};

class PingServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;
   const char* mContent;
   bool mChunked;

public:
   PingServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
      mChunked = pingPong->getConfig()["chunked"]->getBoolean();
   }

   virtual ~PingServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      const char* str = "Pong!";
      int len = 5;

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mChunked)
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "text/plain");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(str, len);
      response->sendBody(&bais, NULL);
      mPingPong->service(len);
   }
};

class ConstByteInputStream : public InputStream
{
protected:
   int mLength;
   const char* mBuffer;
   int mBufsize;
   char* mLocalBuffer;
   bool mFreeBuffer;

public:
   /**
    * Create new input stream.
    *
    * @param length length of stream
    * @param buf data buffer to use or NULL to create one
    * @param bufsize size of buf
    * @param b char to fill buf with if buf is NULL
    */
   ConstByteInputStream(
      int length, const char* buf = NULL, int bufsize = 0, char b = '.') :
      mLength(length),
      mBuffer(buf),
      mBufsize((bufsize == 0) ? 4096 : bufsize),
      mFreeBuffer((buf == NULL) ? true : false)
   {
      if(mBuffer == NULL)
      {
         mBuffer = mLocalBuffer = (char*)malloc(mBufsize);
         memset(mLocalBuffer, b, min(mLength, 4096));
      }
   }

   virtual ~ConstByteInputStream()
   {
      if(mFreeBuffer)
      {
         free(mLocalBuffer);
      }
   }

   virtual int read(char* b, int length)
   {
      // max is 4k or remaining, let higher levels loop
      int max = min(mLength, mBufsize);
      // return max or length
      int rval = min(max, length);
      // reduce remaining
      mLength -= rval;
      memcpy(b, mBuffer, rval);
      return rval;
   }
};

class DataServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;
   string mPath;
   const char* mBuffer;
   int mBufsize;
   bool mChunked;

public:
   DataServicer(
      PingPong* pingPong, const char* path,
      const char* buffer = NULL, int bufsize = 0) :
      HttpRequestServicer(path),
      mPingPong(pingPong),
      mPath(path),
      mBuffer(buffer),
      mBufsize(bufsize)
   {
      mChunked = pingPong->getConfig()["chunked"]->getBoolean();
      if(mPath.length() > 0 && mPath[mPath.length()] != '/')
      {
         mPath.push_back('/');
      }
   }

   virtual ~DataServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      // get length param from value after root path, else 0
      const char* path = request->getHeader()->getPath();
      Url url(path);
      DynamicObject tokens;
      url.getTokenizedPath(tokens, mPath.c_str());
      int len = 0;
      if(tokens->length() > 0)
      {
         len = tokens[0]->getInt32();
      }

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mChunked)
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "text/plain");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      // send const bytes of a specified length
      ConstByteInputStream cbis(len, mBuffer, mBufsize);
      response->sendBody(&cbis, NULL);
      mPingPong->service(len);
   }
};

class StatsServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   StatsServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~StatsServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      Config& c = mPingPong->getConfig();
      // generate stats string
      DynamicObject stats;
      if(c["dynoStats"]->getBoolean())
      {
         stats["dyno"] = DynamicObjectImpl::getStats();
      }
      stats["ping"] = mPingPong->getStats();
      string statsstr = JsonWriter::writeToString(stats);
      int len = statsstr.length();

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mPingPong->getConfig()["chunked"]->getBoolean())
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "application/json");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(statsstr.c_str(), len);
      response->sendBody(&bais, NULL);
   }
};

class ResetServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   ResetServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~ResetServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      mPingPong->reset();
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
   }
};

class QuitServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   QuitServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~QuitServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      mPingPong->quit();
   }
};

static void runPingTest(TestRunner& tr)
{
   tr.test("Ping");

   Config cfg = tr.getApp()->getConfig()["pong"];

   // Stats and control
   PingPong pingPong(cfg);

   // create kernel
   Kernel k;

   // set thread stack size in engine (128k)
   k.getEngine()->getThreadPool()->setThreadStackSize(
      cfg["threadStackSize"]->getUInt32());

   // optional for testing --
   // limit threads to 2: one for accepting, 1 for handling
   //k.getEngine()->getThreadPool()->setPoolSize(2);
   k.getEngine()->getThreadPool()->setPoolSize(cfg["threads"]->getUInt32());

   // start engine
   k.getEngine()->start();

   // create server
   Server server;
   server.setMaxConnectionCount(cfg["maxConnections"]->getInt32());
   InternetAddress address("0.0.0.0", cfg["port"]->getUInt32());

   // create SSL/generic http connection servicer
   HttpConnectionServicer hcs;
//   SslContext context;
//   SslSocketDataPresenter presenter1(&context);
//   NullSocketDataPresenter presenter2;
//   SocketDataPresenterList list(false);
//   list.add(&presenter1);
//   list.add(&presenter2);
   //server.addConnectionService(&address, &hcs);//, &list);
   server.addConnectionService(
      &address, &hcs, NULL, "pong",
      cfg["maxConnections"]->getInt32(),
      cfg["backlog"]->getInt32());

   // create test http request servicer
   NoContentServicer noContentSrv(&pingPong, "/");
   hcs.addRequestServicer(&noContentSrv, false);

   PingServicer ping(&pingPong, "/pong");
   hcs.addRequestServicer(&ping, false);

   const int bufsize = 4096;
   char buf[bufsize];
   memset(buf, '.', bufsize);
   DataServicer data(&pingPong, "/data", buf, bufsize);
   hcs.addRequestServicer(&data, false);

   StatsServicer stats(&pingPong, "/stats");
   hcs.addRequestServicer(&stats, false);

   ResetServicer reset(&pingPong, "/reset");
   hcs.addRequestServicer(&reset, false);

   QuitServicer quit(&pingPong, "/quit");
   hcs.addRequestServicer(&quit, false);

   if(server.start(&k))
   {
      uint64_t num = cfg["num"]->getUInt64();
      MO_INFO("Server started.");
      if(num == 0)
      {
         MO_INFO("Servicing forever. CTRL-C to quit.");
      }
      {
         MO_INFO("Servicing approximately %" PRIu64 " connections.", num);
      }
   }
   else if(Exception::get() != NULL)
   {
      MO_ERROR("Server started with errors=%s\n",
         Exception::get()->getMessage());
   }

   // start timing
   pingPong.reset();

   // either serve for limited time, or wait for lock
   uint32_t time = cfg["time"]->getUInt32();
   if(time != 0)
   {
      Thread::sleep(time);
   }
   else
   {
      pingPong.getLock().wait();
   }

   server.stop();
   MO_INFO("Server stopped.");

   // stop kernel engine
   k.getEngine()->stop();

   tr.passIfNoException();
}

static bool run(TestRunner& tr)
{
   if(tr.isTestEnabled("pong"))
   {
      runPingTest(tr);
   }
   return true;
}

} // end namespace

MO_TEST_MODULE_FN("monarch.tests.pong.test", "1.0", mo_test_pong::run)
<|endoftext|>


<commit_before>#include <cstdio>

#include <vtkCellArray.h>
#include <vtkFloatArray.h>
#include <vtkPoints.h>

#include "proctor/proctor.h"
#include "proctor/detector.h"
#include "proctor/scanning_model_source.h"
#include "proctor/confusion_matrix.h"

#ifdef _MSC_VER
# define snprintf _snprintf
#endif

namespace pcl
{

  namespace proctor
  {

    IndicesPtr
    Proctor::randomSubset(int n, int r)
    {
      IndicesPtr subset (new vector<int>());
      vector<int> bag (n);
      for (int i = 0; i < n; i++) bag[i] = i;
      int edge = n;
      subset->resize(r);
      for (int i = 0; i < r; i++) {
        int pick = rand() % edge;
        (*subset)[i] = bag[pick];
        bag[pick] = bag[--edge];
      }
      return subset;
    }

    void
    Proctor::train(Detector &detector)
    {
      source_->getModelIDs(model_ids_);

      cout << "Proctor beginning training" << endl;

      cout << "[models]" << endl;

      //for (int mi = 0; mi < num_model_ids && mi < Config::num_models; mi++) {
      timer.start();
      const int num_model_ids = model_ids_.size();
#pragma omp parallel for
      for (int mi = 0; mi < Config::num_models; mi++) {
        std::string model_id = model_ids_[mi];
        cout << "Begin scanning model " << mi << " (" << model_id << ")" << endl;
        Scene *scene = new Scene(model_id, source_->getTrainingModel(model_id));
        cout << "Finished scanning model " << mi << " (" << model_id << ")" << endl;
        cout << endl;

        cout << "Begin training model " << mi << " (" << model_id << ")" << endl;
        // TODO Time the training phase
        detector.train(*scene);
        cout << "Finished training model " << mi << " (" << model_id << ")" << endl;
        cout << endl;
      }
      timer.stop(OBTAIN_CLOUD_TRAINING);

      cout << "Proctor finished training" << endl;
    }

    double
    Proctor::test(Detector &detector, unsigned int seed)
    {
      srand(seed);

      source_->resetTestGenerator();

      // run the tests
      memset(confusion, 0, sizeof(confusion));

      std::map<std::string, std::map<std::string, int> > guesses;
      ConfusionMatrix confusion_matrix;

      int num_model_ids = model_ids_.size();
//#pragma omp parallel for
      for (int ni = 0; num_model_ids > 0 && ni < Config::num_trials; ni++) {
        cout << "[test " << ni << "]" << endl;

        std::string truth_id = model_ids_[ni % model_ids_.size()];

        std::map<std::string, int>& guesses_for_id = guesses[truth_id];

        timer.start();
        PointCloud<PointNormal>::Ptr test_cloud = source_->getTestModel(truth_id);
        timer.stop(OBTAIN_CLOUD_TESTING);

        cout << "scanned model " << truth_id << endl;

        timer.start();
        try {
          Scene test_scene(truth_id, test_cloud);
          //std::string guessed_id = detector.query(test_scene, classifier[ni], registration[ni]);
          std::string guessed_id = detector.query(test_scene);

          guesses_for_id[guessed_id] += 1;
          confusion_matrix.increment(truth_id, guessed_id);
          cout << "detector guessed " << guessed_id << endl;
        } catch (exception &e) {
          cout << "Detector exception" << endl;
          cout << e.what() << endl;
          //memset(classifier[ni], 0, sizeof(classifier[ni]));
          //memset(registration[ni], 0, sizeof(registration[ni]));
        }
        timer.stop(DETECTOR_TEST);

        cout << endl;
      }

      printConfusionMatrix(confusion_matrix);

      return confusion_matrix.trace();
    }

    typedef struct {
      int ni;
      int mi;
      double distance;
    } Detection;

    bool
    operator<(const Detection &a, const Detection &b)
    {
      return a.distance < b.distance;
    }

    void
    Proctor::printPrecisionRecall()
    {
      //vector<Detection> detections;
      //Detection d;
      //for (d.ni = 0; d.ni < Config::num_trials; d.ni++) {
        //for (d.mi = 0; d.mi < Config::num_models; d.mi++) {
          //d.distance = registration[d.ni][d.mi];
          //if (!d.distance) continue; // did not attempt registration on this model
          //detections.push_back(d);
        //}
      //}
      //sort(detections.begin(), detections.end());
      //int correct = 0;
      //for (unsigned int di = 0; di < detections.size(); di++) {
        //if (detections[di].mi == scenes[detections[di].ni].mi) {
          //correct++;
          //printf(
            //"%.6f %.6f %g\n",
            //double(correct) / double(di + 1),
            //double(correct) / double(Config::num_trials),
            //detections[di].distance
          //);
        //}
      //}
    }

    void
    Proctor::printClassifierStats()
    {
      //float avg = 0; // average rank of correct id
      //int area = 0; // area under curve of cumulative histogram
      //for (int ni = 0; ni < Config::num_trials; ni++) {
        //int answer = scenes[ni].mi;
        //float votes = classifier[ni][answer];
        //// figure out the rank in this trial
        //int rank = 1;
        //int tie = 0;
        //for (int mi = 0; mi < Config::num_models; mi++) {
          //if (classifier[ni][mi] > votes) rank++;
          //else if (classifier[ni][mi] == votes) tie++;
        //}
        //// contribute to average rank
        //avg += rank + float(tie) / 2;
        //// contribute to area under curve
        //area += Config::num_models - rank + 1;
      //}
      //avg /= Config::num_trials;
      //printf("average vote rank of correct model:                    %0.2f\n", avg);
      //printf("area under cumulative histogram of correct model rank: %d\n", area);
    }

    void
    Proctor::printTimer()
    {
      printf(
        "obtain training clouds: %10.3f sec\n"
        "obtain testing clouds:  %10.3f sec\n"
        "detector training:      %10.3f sec\n"
        "detector testing:       %10.3f sec\n",
        timer[OBTAIN_CLOUD_TRAINING],
        timer[OBTAIN_CLOUD_TESTING],
        timer[DETECTOR_TRAIN],
        timer[DETECTOR_TEST]
      );
    }

    void
    Proctor::printResults(Detector &detector)
    {
      // precision-recall
      printf("[precision-recall]\n");
      printPrecisionRecall();

      // classifier stats
      printf("[classifier stats]\n");
      printClassifierStats();

      // timing
      printf("[timing]\n");
      printTimer();
      printf("[detector timing]\n");
      detector.printTimer();
    }

    void
    Proctor::printConfusionMatrix(ConfusionMatrix &matrix)
    {
      // correct percentage
      printf("[overview]\n");
      printf("%d of %d correct (%.2f%%)\n", matrix.trace(), matrix.total(), float(matrix.trace()) / matrix.total() * 100);

      cout << endl;

      cout << "[confusion matrix]" << endl;
      matrix.printMatrix();

      cout << endl;
    }
  }

}
<commit_msg>Fix the bounds for parallelization via OpenMP<commit_after>#include <cstdio>
#include <algorithm>

#include <vtkCellArray.h>
#include <vtkFloatArray.h>
#include <vtkPoints.h>

#include "proctor/proctor.h"
#include "proctor/detector.h"
#include "proctor/scanning_model_source.h"
#include "proctor/confusion_matrix.h"

#ifdef _MSC_VER
# define snprintf _snprintf
#endif

namespace pcl
{

  namespace proctor
  {

    IndicesPtr
    Proctor::randomSubset(int n, int r)
    {
      IndicesPtr subset (new vector<int>());
      vector<int> bag (n);
      for (int i = 0; i < n; i++) bag[i] = i;
      int edge = n;
      subset->resize(r);
      for (int i = 0; i < r; i++) {
        int pick = rand() % edge;
        (*subset)[i] = bag[pick];
        bag[pick] = bag[--edge];
      }
      return subset;
    }

    void
    Proctor::train(Detector &detector)
    {
      source_->getModelIDs(model_ids_);

      cout << "Proctor beginning training" << endl;

      cout << "[models]" << endl;

      timer.start();
      const int num_model_ids = std::min((int) model_ids_.size(), num_models_);
#pragma omp parallel for
      for (int mi = 0; mi < num_model_ids; mi++) {
        std::string model_id = model_ids_[mi];
        cout << "Begin scanning model " << mi << " (" << model_id << ")" << endl;
        Scene *scene = new Scene(model_id, source_->getTrainingModel(model_id));
        cout << "Finished scanning model " << mi << " (" << model_id << ")" << endl;
        cout << endl;

        cout << "Begin training model " << mi << " (" << model_id << ")" << endl;
        // TODO Time the training phase
        detector.train(*scene);
        cout << "Finished training model " << mi << " (" << model_id << ")" << endl;
        cout << endl;
      }
      timer.stop(OBTAIN_CLOUD_TRAINING);

      cout << "Proctor finished training" << endl;
    }

    double
    Proctor::test(Detector &detector, unsigned int seed)
    {
      srand(seed);

      source_->resetTestGenerator();

      std::map<std::string, std::map<std::string, int> > guesses;
      ConfusionMatrix confusion_matrix;

      int num_model_ids = std::min((int) model_ids_.size(), num_models_);
      if (num_model_ids == 0)
        assert(false);
//#pragma omp parallel for
      for (int ni = 0; ni < num_trials_; ni++) {
        cout << "[test " << ni << "]" << endl;

        std::string truth_id = model_ids_[ni % num_model_ids];

        std::map<std::string, int>& guesses_for_id = guesses[truth_id];

        timer.start();
        PointCloud<PointNormal>::Ptr test_cloud = source_->getTestModel(truth_id);
        timer.stop(OBTAIN_CLOUD_TESTING);

        cout << "scanned model " << truth_id << endl;

        timer.start();
        try {
          Scene test_scene(truth_id, test_cloud);
          //std::string guessed_id = detector.query(test_scene, classifier[ni], registration[ni]);
          std::string guessed_id = detector.query(test_scene);

          guesses_for_id[guessed_id] += 1;
          confusion_matrix.increment(truth_id, guessed_id);
          cout << "detector guessed " << guessed_id << endl;
        } catch (exception &e) {
          cout << "Detector exception" << endl;
          cout << e.what() << endl;
          //memset(classifier[ni], 0, sizeof(classifier[ni]));
          //memset(registration[ni], 0, sizeof(registration[ni]));
        }
        timer.stop(DETECTOR_TEST);

        cout << endl;
      }

      printConfusionMatrix(confusion_matrix);

      return confusion_matrix.trace();
    }

    typedef struct {
      int ni;
      int mi;
      double distance;
    } Detection;

    bool
    operator<(const Detection &a, const Detection &b)
    {
      return a.distance < b.distance;
    }

    void
    Proctor::printPrecisionRecall()
    {
      //vector<Detection> detections;
      //Detection d;
      //for (d.ni = 0; d.ni < Config::num_trials; d.ni++) {
        //for (d.mi = 0; d.mi < Config::num_models; d.mi++) {
          //d.distance = registration[d.ni][d.mi];
          //if (!d.distance) continue; // did not attempt registration on this model
          //detections.push_back(d);
        //}
      //}
      //sort(detections.begin(), detections.end());
      //int correct = 0;
      //for (unsigned int di = 0; di < detections.size(); di++) {
        //if (detections[di].mi == scenes[detections[di].ni].mi) {
          //correct++;
          //printf(
            //"%.6f %.6f %g\n",
            //double(correct) / double(di + 1),
            //double(correct) / double(Config::num_trials),
            //detections[di].distance
          //);
        //}
      //}
    }

    void
    Proctor::printClassifierStats()
    {
      //float avg = 0; // average rank of correct id
      //int area = 0; // area under curve of cumulative histogram
      //for (int ni = 0; ni < Config::num_trials; ni++) {
        //int answer = scenes[ni].mi;
        //float votes = classifier[ni][answer];
        //// figure out the rank in this trial
        //int rank = 1;
        //int tie = 0;
        //for (int mi = 0; mi < Config::num_models; mi++) {
          //if (classifier[ni][mi] > votes) rank++;
          //else if (classifier[ni][mi] == votes) tie++;
        //}
        //// contribute to average rank
        //avg += rank + float(tie) / 2;
        //// contribute to area under curve
        //area += Config::num_models - rank + 1;
      //}
      //avg /= Config::num_trials;
      //printf("average vote rank of correct model:                    %0.2f\n", avg);
      //printf("area under cumulative histogram of correct model rank: %d\n", area);
    }

    void
    Proctor::printTimer()
    {
      printf(
        "obtain training clouds: %10.3f sec\n"
        "obtain testing clouds:  %10.3f sec\n"
        "detector training:      %10.3f sec\n"
        "detector testing:       %10.3f sec\n",
        timer[OBTAIN_CLOUD_TRAINING],
        timer[OBTAIN_CLOUD_TESTING],
        timer[DETECTOR_TRAIN],
        timer[DETECTOR_TEST]
      );
    }

    void
    Proctor::printResults(Detector &detector)
    {
      // precision-recall
      printf("[precision-recall]\n");
      printPrecisionRecall();

      // classifier stats
      printf("[classifier stats]\n");
      printClassifierStats();

      // timing
      printf("[timing]\n");
      printTimer();
      printf("[detector timing]\n");
      detector.printTimer();
    }

    void
    Proctor::printConfusionMatrix(ConfusionMatrix &matrix)
    {
      // correct percentage
      printf("[overview]\n");
      printf("%d of %d correct (%.2f%%)\n", matrix.trace(), matrix.total(), float(matrix.trace()) / matrix.total() * 100);

      cout << endl;

      cout << "[confusion matrix]" << endl;
      matrix.printMatrix();

      cout << endl;
    }
  }

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: SlsClipboard.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 14:01:01 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef SD_SLIDESORTER_CLIPBOARD
#define SD_SLIDESORTER_CLIPBOARD

#include "ViewClipboard.hxx"

#include <sal/types.h>
#include <tools/solar.h>
#include <svx/svdpage.hxx>

#include <set>

class SfxRequest;
class Window;

struct AcceptDropEvent;
class DropTargetHelper;
struct ExecuteDropEvent;
class Point;
class SdPage;
class Window;

namespace sd {
class Window;
}

namespace sd { namespace slidesorter { namespace model {
class PageDescriptor;
} } }

namespace sd { namespace slidesorter { namespace controller {

class SlideSorterController;

class Clipboard
    : public ViewClipboard
{
public:
    Clipboard (SlideSorterController& rController);
    ~Clipboard (void);

    void HandleSlotCall (SfxRequest& rRequest);

    void DoCut (::Window* pWindow = 0);
    void DoCopy (::Window* pWindow = 0);
    void DoPaste (::Window* pWindow = 0);

    void StartDrag (
        const Point& rDragPt,
        ::Window* pWindow );

    void DragFinished (
        sal_Int8 nDropAction);

    sal_Int8 AcceptDrop (
        const AcceptDropEvent& rEvt,
        DropTargetHelper& rTargetHelper,
        ::sd::Window* pTargetWindow = NULL,
        USHORT nPage = SDRPAGE_NOTFOUND,
        USHORT nLayer = SDRPAGE_NOTFOUND );

    sal_Int8 ExecuteDrop (
        const ExecuteDropEvent& rEvt,
        DropTargetHelper& rTargetHelper,
        ::sd::Window* pTargetWindow = NULL,
        USHORT nPage = SDRPAGE_NOTFOUND,
        USHORT nLayer = SDRPAGE_NOTFOUND);

protected:
    virtual USHORT DetermineInsertPosition (
        const SdTransferable& rTransferable);

    virtual USHORT InsertSlides (
        const SdTransferable& rTransferable,
        USHORT nInsertPosition);

private:
    SlideSorterController& mrController;

    typedef ::std::vector<SdPage*> PageList;
    /** Remember the pages that are dragged to another document or to
        another place in the same document so that they can be removed after
        a move operation.
    */
    PageList maPagesToRemove;

    /** Remember the pages inserted from another document or another place
        in the same document so that they can be selected after the
        drag-and-drop operation is completed.
    */
    PageList maPagesToSelect;

    /** When pages are moved or copied then the selection of the slide
        sorter has to be updated.  This flag is used to remember whether the
        selection has to be updated or can stay as it is (FALSE).
    */
    bool mbUpdateSelectionPending;

    void CreateSlideTransferable (
        ::Window* pWindow,
        bool bDrag);

    /** Select the pages stored in the maPagesToSelect member.  The list in
        the member is cleared afterwards.
    */
    void SelectPages (void);

    /** Determine the position of where to insert the pages in the current
        transferable of the sd module.
        @param pWindow
            This window is used as parent for dialogs that have to be shown
            to the user.
        @return
            The index in the range [0,n] (both inclusive) with n the number
            of pages is returned.
    */
    sal_Int32 GetInsertionPosition (::Window* pWindow);

    /** Paste the pages of the transferable of the sd module at the given
        position.
        @param nInsertPosition
            The position at which to insert the pages.  The valid range is
            [0,n] (both inclusive) with n the number of pages in the
            document.
        @return
            The number of inserted pages is returned.
    */
    sal_Int32 PasteTransferable (sal_Int32 nInsertPosition);

    /** Select a range of pages of the model.  Typicall usage is the
        selection of newly inserted pages.
        @param nFirstIndex
            The index of the first page to select.
        @param nPageCount
            The number of pages to select.
    */
    void SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount);
};

} } } // end of namespace ::sd::slidesorter::controller

#endif

<commit_msg>INTEGRATION: CWS impress44 (1.4.10); FILE MERGED 2005/04/05 08:56:34 af 1.4.10.1: #i46672# Added DoDelete().<commit_after>/*************************************************************************
 *
 *  $RCSfile: SlsClipboard.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2005-04-12 16:58:17 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef SD_SLIDESORTER_CLIPBOARD
#define SD_SLIDESORTER_CLIPBOARD

#include "ViewClipboard.hxx"

#include <sal/types.h>
#include <tools/solar.h>
#include <svx/svdpage.hxx>

#include <set>

class SfxRequest;
class Window;

struct AcceptDropEvent;
class DropTargetHelper;
struct ExecuteDropEvent;
class Point;
class SdPage;
class Window;

namespace sd {
class Window;
}

namespace sd { namespace slidesorter { namespace model {
class PageDescriptor;
} } }

namespace sd { namespace slidesorter { namespace controller {

class SlideSorterController;

class Clipboard
    : public ViewClipboard
{
public:
    Clipboard (SlideSorterController& rController);
    ~Clipboard (void);

    void HandleSlotCall (SfxRequest& rRequest);

    void DoCut (::Window* pWindow = 0);
    void DoCopy (::Window* pWindow = 0);
    void DoPaste (::Window* pWindow = 0);
    void DoDelete (::Window* pWindow = 0);

    void StartDrag (
        const Point& rDragPt,
        ::Window* pWindow );

    void DragFinished (
        sal_Int8 nDropAction);

    sal_Int8 AcceptDrop (
        const AcceptDropEvent& rEvt,
        DropTargetHelper& rTargetHelper,
        ::sd::Window* pTargetWindow = NULL,
        USHORT nPage = SDRPAGE_NOTFOUND,
        USHORT nLayer = SDRPAGE_NOTFOUND );

    sal_Int8 ExecuteDrop (
        const ExecuteDropEvent& rEvt,
        DropTargetHelper& rTargetHelper,
        ::sd::Window* pTargetWindow = NULL,
        USHORT nPage = SDRPAGE_NOTFOUND,
        USHORT nLayer = SDRPAGE_NOTFOUND);

protected:
    virtual USHORT DetermineInsertPosition (
        const SdTransferable& rTransferable);

    virtual USHORT InsertSlides (
        const SdTransferable& rTransferable,
        USHORT nInsertPosition);

private:
    SlideSorterController& mrController;

    typedef ::std::vector<SdPage*> PageList;
    /** Remember the pages that are dragged to another document or to
        another place in the same document so that they can be removed after
        a move operation.
    */
    PageList maPagesToRemove;

    /** Remember the pages inserted from another document or another place
        in the same document so that they can be selected after the
        drag-and-drop operation is completed.
    */
    PageList maPagesToSelect;

    /** When pages are moved or copied then the selection of the slide
        sorter has to be updated.  This flag is used to remember whether the
        selection has to be updated or can stay as it is (FALSE).
    */
    bool mbUpdateSelectionPending;

    void CreateSlideTransferable (
        ::Window* pWindow,
        bool bDrag);

    /** Select the pages stored in the maPagesToSelect member.  The list in
        the member is cleared afterwards.
    */
    void SelectPages (void);

    /** Determine the position of where to insert the pages in the current
        transferable of the sd module.
        @param pWindow
            This window is used as parent for dialogs that have to be shown
            to the user.
        @return
            The index in the range [0,n] (both inclusive) with n the number
            of pages is returned.
    */
    sal_Int32 GetInsertionPosition (::Window* pWindow);

    /** Paste the pages of the transferable of the sd module at the given
        position.
        @param nInsertPosition
            The position at which to insert the pages.  The valid range is
            [0,n] (both inclusive) with n the number of pages in the
            document.
        @return
            The number of inserted pages is returned.
    */
    sal_Int32 PasteTransferable (sal_Int32 nInsertPosition);

    /** Select a range of pages of the model.  Typicall usage is the
        selection of newly inserted pages.
        @param nFirstIndex
            The index of the first page to select.
        @param nPageCount
            The number of pages to select.
    */
    void SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount);
};

} } } // end of namespace ::sd::slidesorter::controller

#endif

<|endoftext|>


<commit_before>/** @file poisson2_example.cpp

    @brief Tutorial on how to use expression assembler to solve the Poisson equation

    This file is part of the G+Smo library.

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at http://mozilla.org/MPL/2.0/.

    Author(s): A. Mantzaflaris
*/

//! [Include namespace]
#include <gismo.h>

#  define MatExprType  auto

namespace gismo{
namespace expr{

template<class E>
class mygrad_expr : public _expr<mygrad_expr<E> >
{
    typename E::Nested_t _u;
public:
    enum{ Space = E::Space };

    typedef typename E::Scalar Scalar;

    mygrad_expr(const E & u) : _u(u)
    { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}

    MatExprType eval(const index_t k) const
    {
        // numActive x dim
        return _u.data().values[1].reshapeCol(k, cols(), rows()).transpose();
    }

    index_t rows() const
    {
        //return _u.data().values[0].rows();
        return _u.data().values[1].rows() / cols();
    }
    //index_t rows() const { return _u.data().actives.size(); }
    //index_t rows() const { return _u.rows(); }

    //index_t rows() const { return _u.source().targetDim() is wrong }
    index_t cols() const { return _u.source().domainDim(); }

    void setFlag() const
    {
        _u.data().flags |= NEED_GRAD;
        if (_u.composed() )
            _u.mapData().flags |= NEED_VALUE;
    }

    void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
    {
        //GISMO_ASSERT(NULL!=m_fd, "FeVariable: FuncData member not registered");
        evList.push_sorted_unique(&_u.source());
        _u.data().flags |= NEED_GRAD;
        if (_u.composed() )
            _u.mapData().flags |= NEED_VALUE;
    }

    const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
    const gsFeSpace<Scalar> & colVar() const
    {return gsNullExpr<Scalar>::get();}

    static constexpr bool rowSpan() {return E::rowSpan(); }
    static constexpr bool colSpan() {return false;}

    void print(std::ostream &os) const { os << "grad("; _u.print(os); os <<")"; }
};

// Comments for var1:
// - TODO: dimensionm indep. later on
template<class E>
class var1_expr : public _expr<var1_expr<E> >
{
public:
    typedef typename E::Scalar Scalar;

private:

    typename E::Nested_t _u;
    typename gsGeometryMap<Scalar>::Nested_t _G;

public:
    enum{ Space = E::Space };

    var1_expr(const E & u, const gsGeometryMap<Scalar> & G) : _u(u), _G(G) { }

    mutable gsMatrix<Scalar> res;

    mutable gsMatrix<Scalar> bGrads, cJac;
    mutable gsVector<Scalar,3> m_v, normal;

    // helper function
    static inline gsVector<Scalar,3> vecFun(index_t pos, Scalar val)
    {
        gsVector<Scalar,3> result = gsVector<Scalar,3>::Zero();
        result[pos] = val;
        return result;
    }

    MatExprType eval(const index_t k) const
    {
        res.resize(rows(), cols());
        const index_t A = rows()/cols(); // note: rows/cols is the number of actives

        normal = _G.data().outNormals.col(k);
        bGrads = _u.data().values[1].col(k);
        cJac = _G.data().values[1].reshapeCol(k, _G.data().dim.first, _G.data().dim.second).transpose();
        const Scalar measure =  _G.data().measures.at(k);

        for (index_t d = 0; d!= cols(); ++d) // for all basis functions (1)
        {
            const short_t s = d*A;
            for (index_t j = 0; j!= A; ++j) // for all basis functions (2)
            {
                // Jac(u) ~ Jac(G) with alternating signs ?..
                m_v.noalias() = vecFun(d, bGrads.at(2*j  ) ).cross( cJac.col(1).template head<3>() )
                              - vecFun(d, bGrads.at(2*j+1) ).cross( cJac.col(0).template head<3>() );

                // ---------------  First variation of the normal
                res.row(s+j).noalias() = (m_v - ( normal.dot(m_v) ) * normal).transpose() / measure;
            }
        }

        return res;
    }

    index_t rows() const
    {
        return cols() * _u.data().values[1].rows() / _u.source().domainDim();
    }

    index_t cols() const { return _u.dim(); }

    void setFlag() const
    {
        _u.data().flags |= NEED_GRAD;
        _G.data().flags |= NEED_OUTER_NORMAL | NEED_DERIV | NEED_MEASURE;
    }

    void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
    {
        evList.push_sorted_unique(&_u.source());
        _u.data().flags |= NEED_GRAD;
        _G.data().flags |= NEED_OUTER_NORMAL | NEED_DERIV | NEED_MEASURE;
    }

    const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
    const gsFeSpace<Scalar> & colVar() const
    {return gsNullExpr<Scalar>::get();}

    static constexpr bool rowSpan() {return E::rowSpan(); }
    static constexpr bool colSpan() {return false;}

    void print(std::ostream &os) const { os << "var1("; _u.print(os); os <<")"; }
};

// template<class E>
// class var2_expr : public _expr<var2_expr<E> >
// {
//     typename E::Nested_t _u;
//     typename E::Nested_t _v;
//     typename gsGeometryMap<T>::Nested_t _G;

// public:
//     enum{ Space = E::Space };

//     typedef typename E::Scalar Scalar;

//     var2_expr(const E & u) : _u(u)
//     { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}

//     MatExprType eval(const index_t k) const
//     {
//         // numActive x dim
//         return _u.data().values[1].reshapeCol(k, cols(), rows()).transpose();
//     }

//     index_t rows() const
//     {
//         //return _u.data().values[0].rows();
//         return _u.data().values[1].rows() / cols();
//     }
//     //index_t rows() const { return _u.data().actives.size(); }
//     //index_t rows() const { return _u.rows(); }

//     //index_t rows() const { return _u.source().targetDim() is wrong }
//     index_t cols() const { return _u.source().domainDim(); }

//     void setFlag() const
//     {
//         _u.data().flags |= NEED_GRAD;
//         _G.data().flags |= NEED_OUTER_NORMAL;
//         if (_u.composed() )
//             _u.mapData().flags |= NEED_VALUE;
//     }

//     void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
//     {
//         //GISMO_ASSERT(NULL!=m_fd, "FeVariable: FuncData member not registered");
//         evList.push_sorted_unique(&_u.source());
//         _u.data().flags |= NEED_GRAD;
//         if (_u.composed() )
//             _u.mapData().flags |= NEED_VALUE;
//     }

//     const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
//     const gsFeSpace<Scalar> & colVar() const
//     {return gsNullExpr<Scalar>::get();}

//     static constexpr bool rowSpan() {return E::rowSpan(); }
//     static constexpr bool colSpan() {return false;}

//     void print(std::ostream &os) const { os << "grad("; _u.print(os); os <<")"; }
// };

// template<class E>
// class hessdot_expr : public _expr<hessdot_expr<E> >
// {
//     typename E::Nested_t _u;
//     typename gsGeometryMap<T>::Nested_t _G;

// public:
//     enum{ Space = E::Space };

//     typedef typename E::Scalar Scalar;

//     hessdot_expr(const E & u) : _u(u)
//     { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}

// !    MatExprType eval(const index_t k) const
//     {
//         // numActive x dim
//         return _u.data().values[1].reshapeCol(k, cols(), rows()).transpose();
//     }

// !    index_t rows() const
//     {
//         //return _u.data().values[0].rows();
//         return _u.data().values[1].rows() / cols();
//     }
//     //index_t rows() const { return _u.data().actives.size(); }
//     //index_t rows() const { return _u.rows(); }

//     //index_t rows() const { return _u.source().targetDim() is wrong }
// !    index_t cols() const { return _u.source().domainDim(); }

//     void setFlag() const
//     {
//         _u.data().flags |= NEED_2ND_DER;
//         _G.data().flags |= NEED_OUTER_NORMAL;
//     }

//     void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
//     {
//         //GISMO_ASSERT(NULL!=m_fd, "FeVariable: FuncData member not registered");
//         evList.push_sorted_unique(&_u.source());
//         _u.data().flags |= NEED_GRAD;
//         if (_u.composed() )
//             _u.mapData().flags |= NEED_VALUE;
//     }

// !    const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
// !    const gsFeSpace<Scalar> & colVar() const
//     {return gsNullExpr<Scalar>::get();}

//     static constexpr bool rowSpan() {return E::rowSpan(); }
//     static constexpr bool colSpan() {return false;}

//     void print(std::ostream &os) const { os << "grad("; _u.print(os); os <<")"; }
// };

template<class E> EIGEN_STRONG_INLINE
mygrad_expr<E> mygrad(const E & u) { return mygrad_expr<E>(u); }

template<class E> EIGEN_STRONG_INLINE
var1_expr<E> var1(const E & u, const gsGeometryMap<typename E::Scalar> & G) { return var1_expr<E>(u, G); }

// template<class E> EIGEN_STRONG_INLINE
// mygrad_expr<E> var2(const E & u, const E & v, const gsGeometryMap<T> & G) { return var2_expr<E>(u, v, G); }

// template<class E> EIGEN_STRONG_INLINE
// mygrad_expr<E> hessdot(const E & u, const gsGeometryMap<T> & G) { return hessdot_expr<E>(u, G); }

}}

using namespace gismo;

//! [Include namespace]

int main(int argc, char *argv[])
{
    //! [Parse command line]
    bool plot = false;
    index_t numRefine  = 1;
    index_t numElevate = 0;
    bool last = false;
    std::string fn("pde/poisson2d_bvp.xml");

    gsCmdLine cmd("Tutorial on solving a Poisson problem.");
    cmd.addInt( "e", "degreeElevation",
                "Number of degree elevation steps to perform before solving (0: equalize degree in all directions)", numElevate );
    cmd.addInt( "r", "uniformRefine", "Number of Uniform h-refinement steps to perform before solving",  numRefine );
    cmd.addString( "f", "file", "Input XML file", fn );
    cmd.addSwitch("last", "Solve solely for the last level of h-refinement", last);
    cmd.addSwitch("plot", "Create a ParaView visualization file with the solution", plot);

    try { cmd.getValues(argc,argv); } catch (int rv) { return rv; }
    //! [Parse command line]

    //! [Read input file]

    gsFileData<> fd(fn);
    gsInfo << "Loaded file "<< fd.lastPath() <<"\n";

    gsMultiPatch<> mp;
    fd.getId(0, mp); // id=0: Multipatch domain

    //! [Read input file]

    //! [Refinement]
    gsMultiBasis<> dbasis(mp);

    // Elevate and p-refine the basis to order p + numElevate
    // where p is the highest degree in the bases
    dbasis.setDegree( dbasis.maxCwiseDegree() + numElevate);

    // h-refine each basis
    if (last)
    {
        for (int r =0; r < numRefine-1; ++r)
            dbasis.uniformRefine();
        numRefine = 0;
    }

    mp.embed(3);
    gsInfo << "Patches: "<< mp.nPatches() <<", degree: "<< dbasis.minCwiseDegree() <<"\n";
    //! [Refinement]

    //! [Problem setup]
    gsExprAssembler<> A(1,1);

    //gsInfo<<"Active options:\n"<< A.options() <<"\n";
    typedef gsExprAssembler<>::geometryMap geometryMap;
    typedef gsExprAssembler<>::variable    variable;
    typedef gsExprAssembler<>::space       space;
    typedef gsExprAssembler<>::solution    solution;

    // Elements used for numerical integration
    A.setIntegrationElements(dbasis);
    gsExprEvaluator<> ev(A);

    // Set the geometry map
    geometryMap G = A.getMap(mp);

    // Set the discretization space
    space u = A.getSpace(dbasis, 3);
    u.setInterfaceCont(0);

    // Solution vector and solution variable
    gsMatrix<> solVector;
    solution u_sol = A.getSolution(u, solVector);

    gsSparseSolver<>::CGDiagonal solver;

    //! [Problem setup]

    //! [Solver loop]
    gsVector<> l2err(numRefine+1), h1err(numRefine+1);
    gsInfo<< "(dot1=assembled, dot2=solved, dot3=got_error)\n"
        "\nDoFs: ";
    for (int r=0; r<=numRefine; ++r)
    {
        dbasis.uniformRefine();

        // Initialize the system
        A.initSystem();

        gsInfo<< A.numDofs() <<std::flush;

        // Compute the system matrix and right-hand side
//        A.assemble( mygrad(u)*jac(G).ginv() * (mygrad(u)*jac(G).ginv()).tr() * meas(G), u * ff * meas(G) );

        A.assemble( var1(u,G) * var1(u,G).tr() );
        //gsInfo<< A.rhs().transpose() <<"\n";
        gsInfo<< A.matrix().toDense() <<"\n";

    } //for loop

    return EXIT_SUCCESS;

}// end main
<commit_msg>fix example<commit_after>/** @file poisson2_example.cpp

    @brief Tutorial on how to use expression assembler to solve the Poisson equation

    This file is part of the G+Smo library.

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at http://mozilla.org/MPL/2.0/.

    Author(s): A. Mantzaflaris
*/

//! [Include namespace]
#include <gismo.h>

#  define MatExprType  auto

namespace gismo{
namespace expr{

template<class E>
class mygrad_expr : public _expr<mygrad_expr<E> >
{
    typename E::Nested_t _u;
public:
    enum{ Space = E::Space };

    typedef typename E::Scalar Scalar;

    mygrad_expr(const E & u) : _u(u)
    { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}

    MatExprType eval(const index_t k) const
    {
        // numActive x dim
        return _u.data().values[1].reshapeCol(k, cols(), rows()).transpose();
    }

    index_t rows() const
    {
        //return _u.data().values[0].rows();
        return _u.data().values[1].rows() / cols();
    }
    //index_t rows() const { return _u.data().actives.size(); }
    //index_t rows() const { return _u.rows(); }

    //index_t rows() const { return _u.source().targetDim() is wrong }
    index_t cols() const { return _u.source().domainDim(); }

    void setFlag() const
    {
        _u.data().flags |= NEED_GRAD;
        if (_u.composed() )
            _u.mapData().flags |= NEED_VALUE;
    }

    void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
    {
        //GISMO_ASSERT(NULL!=m_fd, "FeVariable: FuncData member not registered");
        evList.push_sorted_unique(&_u.source());
        _u.data().flags |= NEED_GRAD;
        if (_u.composed() )
            _u.mapData().flags |= NEED_VALUE;
    }

    const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
    const gsFeSpace<Scalar> & colVar() const
    {return gsNullExpr<Scalar>::get();}

    static constexpr bool rowSpan() {return E::rowSpan(); }
    static constexpr bool colSpan() {return false;}

    void print(std::ostream &os) const { os << "grad("; _u.print(os); os <<")"; }
};

// Comments for var1:
// - TODO: dimensionm indep. later on
template<class E>
class var1_expr : public _expr<var1_expr<E> >
{
public:
    typedef typename E::Scalar Scalar;

private:

    typename E::Nested_t _u;
    typename gsGeometryMap<Scalar>::Nested_t _G;

public:
    enum{ Space = E::Space };

    var1_expr(const E & u, const gsGeometryMap<Scalar> & G) : _u(u), _G(G) { }

    mutable gsMatrix<Scalar> res;

    mutable gsMatrix<Scalar> bGrads, cJac;
    mutable gsVector<Scalar,3> m_v, normal;

    // helper function
    static inline gsVector<Scalar,3> vecFun(index_t pos, Scalar val)
    {
        gsVector<Scalar,3> result = gsVector<Scalar,3>::Zero();
        result[pos] = val;
        return result;
    }

    MatExprType eval(const index_t k) const
    {
        res.resize(rows(), cols());
        const index_t A = rows()/cols(); // note: rows/cols is the number of actives

        normal = _G.data().outNormals.col(k);// not normalized to unit length
        bGrads = _u.data().values[1].col(k);
        cJac = _G.data().values[1].reshapeCol(k, _G.data().dim.first, _G.data().dim.second).transpose();
        const Scalar measure =  _G.data().measures.at(k);

        for (index_t d = 0; d!= cols(); ++d) // for all basis functions (1)
        {
            const short_t s = d*A;
            for (index_t j = 0; j!= A; ++j) // for all basis functions (2)
            {
                // Jac(u) ~ Jac(G) with alternating signs ?..
                m_v.noalias() = vecFun(d, bGrads.at(2*j  ) ).cross( cJac.col(1).template head<3>() )
                              - vecFun(d, bGrads.at(2*j+1) ).cross( cJac.col(0).template head<3>() );

                // ---------------  First variation of the normal
                res.row(s+j).noalias() = (m_v - ( normal.dot(m_v) ) * normal).transpose() / measure;
            }
        }

        gsDebugVar(res);
        return res;
    }

    index_t rows() const
    {
        return cols() * _u.data().values[1].rows() / _u.source().domainDim();
    }

    index_t cols() const { return _u.dim(); }

    void setFlag() const
    {
        _u.data().flags |= NEED_GRAD;
        _G.data().flags |= NEED_OUTER_NORMAL | NEED_DERIV | NEED_MEASURE;
    }

    void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
    {
        evList.push_sorted_unique(&_u.source());
        _u.data().flags |= NEED_GRAD;
        _G.data().flags |= NEED_OUTER_NORMAL | NEED_DERIV | NEED_MEASURE;
    }

    const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
    const gsFeSpace<Scalar> & colVar() const
    {return gsNullExpr<Scalar>::get();}

    static constexpr bool rowSpan() {return E::rowSpan(); }
    static constexpr bool colSpan() {return false;}

    void print(std::ostream &os) const { os << "var1("; _u.print(os); os <<")"; }
};

// template<class E>
// class var2_expr : public _expr<var2_expr<E> >
// {
//     typename E::Nested_t _u;
//     typename E::Nested_t _v;
//     typename gsGeometryMap<T>::Nested_t _G;

// public:
//     enum{ Space = E::Space };

//     typedef typename E::Scalar Scalar;

//     var2_expr(const E & u) : _u(u)
//     { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}

//     MatExprType eval(const index_t k) const
//     {
//         // numActive x dim
//         return _u.data().values[1].reshapeCol(k, cols(), rows()).transpose();
//     }

//     index_t rows() const
//     {
//         //return _u.data().values[0].rows();
//         return _u.data().values[1].rows() / cols();
//     }
//     //index_t rows() const { return _u.data().actives.size(); }
//     //index_t rows() const { return _u.rows(); }

//     //index_t rows() const { return _u.source().targetDim() is wrong }
//     index_t cols() const { return _u.source().domainDim(); }

//     void setFlag() const
//     {
//         _u.data().flags |= NEED_GRAD;
//         _G.data().flags |= NEED_OUTER_NORMAL;
//         if (_u.composed() )
//             _u.mapData().flags |= NEED_VALUE;
//     }

//     void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
//     {
//         //GISMO_ASSERT(NULL!=m_fd, "FeVariable: FuncData member not registered");
//         evList.push_sorted_unique(&_u.source());
//         _u.data().flags |= NEED_GRAD;
//         if (_u.composed() )
//             _u.mapData().flags |= NEED_VALUE;
//     }

//     const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
//     const gsFeSpace<Scalar> & colVar() const
//     {return gsNullExpr<Scalar>::get();}

//     static constexpr bool rowSpan() {return E::rowSpan(); }
//     static constexpr bool colSpan() {return false;}

//     void print(std::ostream &os) const { os << "grad("; _u.print(os); os <<")"; }
// };

// template<class E>
// class hessdot_expr : public _expr<hessdot_expr<E> >
// {
//     typename E::Nested_t _u;
//     typename gsGeometryMap<T>::Nested_t _G;

// public:
//     enum{ Space = E::Space };

//     typedef typename E::Scalar Scalar;

//     hessdot_expr(const E & u) : _u(u)
//     { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}

// !    MatExprType eval(const index_t k) const
//     {
//         // numActive x dim
//         return _u.data().values[1].reshapeCol(k, cols(), rows()).transpose();
//     }

// !    index_t rows() const
//     {
//         //return _u.data().values[0].rows();
//         return _u.data().values[1].rows() / cols();
//     }
//     //index_t rows() const { return _u.data().actives.size(); }
//     //index_t rows() const { return _u.rows(); }

//     //index_t rows() const { return _u.source().targetDim() is wrong }
// !    index_t cols() const { return _u.source().domainDim(); }

//     void setFlag() const
//     {
//         _u.data().flags |= NEED_2ND_DER;
//         _G.data().flags |= NEED_OUTER_NORMAL;
//     }

//     void parse(gsSortedVector<const gsFunctionSet<Scalar>*> & evList) const
//     {
//         //GISMO_ASSERT(NULL!=m_fd, "FeVariable: FuncData member not registered");
//         evList.push_sorted_unique(&_u.source());
//         _u.data().flags |= NEED_GRAD;
//         if (_u.composed() )
//             _u.mapData().flags |= NEED_VALUE;
//     }

// !    const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
// !    const gsFeSpace<Scalar> & colVar() const
//     {return gsNullExpr<Scalar>::get();}

//     static constexpr bool rowSpan() {return E::rowSpan(); }
//     static constexpr bool colSpan() {return false;}

//     void print(std::ostream &os) const { os << "grad("; _u.print(os); os <<")"; }
// };

template<class E> EIGEN_STRONG_INLINE
mygrad_expr<E> mygrad(const E & u) { return mygrad_expr<E>(u); }

template<class E> EIGEN_STRONG_INLINE
var1_expr<E> var1(const E & u, const gsGeometryMap<typename E::Scalar> & G) { return var1_expr<E>(u, G); }

// template<class E> EIGEN_STRONG_INLINE
// mygrad_expr<E> var2(const E & u, const E & v, const gsGeometryMap<T> & G) { return var2_expr<E>(u, v, G); }

// template<class E> EIGEN_STRONG_INLINE
// mygrad_expr<E> hessdot(const E & u, const gsGeometryMap<T> & G) { return hessdot_expr<E>(u, G); }

}}

using namespace gismo;

//! [Include namespace]

int main(int argc, char *argv[])
{
    //! [Parse command line]
    bool plot = false;
    index_t numRefine  = 1;
    index_t numElevate = 0;
    bool last = false;
    std::string fn("pde/poisson2d_bvp.xml");

    gsCmdLine cmd("Tutorial on solving a Poisson problem.");
    cmd.addInt( "e", "degreeElevation",
                "Number of degree elevation steps to perform before solving (0: equalize degree in all directions)", numElevate );
    cmd.addInt( "r", "uniformRefine", "Number of Uniform h-refinement steps to perform before solving",  numRefine );
    cmd.addString( "f", "file", "Input XML file", fn );
    cmd.addSwitch("last", "Solve solely for the last level of h-refinement", last);
    cmd.addSwitch("plot", "Create a ParaView visualization file with the solution", plot);

    try { cmd.getValues(argc,argv); } catch (int rv) { return rv; }
    //! [Parse command line]

    //! [Read input file]

    gsFileData<> fd(fn);
    gsInfo << "Loaded file "<< fd.lastPath() <<"\n";

    gsMultiPatch<> mp;

    // Annulus
    //fd.getId(0, mp); // id=0: Multipatch domain

    mp.addPatch( gsNurbsCreator<>::BSplineSquare(1) ); // degree

    //! [Read input file]

    //! [Refinement]
    gsMultiBasis<> dbasis(mp);

    // Elevate and p-refine the basis to order p + numElevate
    // where p is the highest degree in the bases
    dbasis.setDegree( dbasis.maxCwiseDegree() + numElevate);

    // h-refine each basis
    if (last)
    {
        for (int r =0; r < numRefine-1; ++r)
            dbasis.uniformRefine();
        numRefine = 0;
    }

    mp.embed(3);
    gsInfo << "Patches: "<< mp.nPatches() <<", degree: "<< dbasis.minCwiseDegree() <<"\n";
    //! [Refinement]

    //! [Problem setup]
    gsExprAssembler<> A(1,1);

    //gsInfo<<"Active options:\n"<< A.options() <<"\n";
    typedef gsExprAssembler<>::geometryMap geometryMap;
    typedef gsExprAssembler<>::variable    variable;
    typedef gsExprAssembler<>::space       space;
    typedef gsExprAssembler<>::solution    solution;

    // Elements used for numerical integration
    A.setIntegrationElements(dbasis);
    gsExprEvaluator<> ev(A);

    // Set the geometry map
    geometryMap G = A.getMap(mp);

    // Set the discretization space
    space u = A.getSpace(dbasis, 3);
    u.setInterfaceCont(0);

    // Solution vector and solution variable
    gsMatrix<> solVector;
    solution u_sol = A.getSolution(u, solVector);

    gsSparseSolver<>::CGDiagonal solver;

    //! [Problem setup]

    //! [Solver loop]
    gsVector<> l2err(numRefine+1), h1err(numRefine+1);
    gsInfo<< "(dot1=assembled, dot2=solved, dot3=got_error)\n"
        "\nDoFs: ";
    for (int r=0; r<=numRefine; ++r)
    {
        dbasis.uniformRefine();

        // Initialize the system
        A.initSystem();

        gsInfo<< A.numDofs() <<"\n"<<std::flush;

        // Compute the system matrix and right-hand side
//        A.assemble( mygrad(u)*jac(G).ginv() * (mygrad(u)*jac(G).ginv()).tr() * meas(G), u * ff * meas(G) );

        //A.assemble( var1(u,G) * var1(u,G).tr() );

        A.assemble( var1(u,G)[0] );

        gsInfo<< A.rhs().transpose() <<"\n";
        //gsInfo<< A.matrix().toDense().diagonal().transpose() <<"\n";

    } //for loop

    return EXIT_SUCCESS;

}// end main
<|endoftext|>