<commit_before>#ifndef TEST_MODULE_H
#define TEST_MODULE_H

#include "nnlib/nn/module.hpp"
using namespace std;
using namespace nnlib;

template <template <typename> class M, typename T = double>
class ModuleTests
{
public:
	static void run(const std::string &name, M<T> &module, const Tensor<T> &sampleInput, bool randomizeInput = true)
	{
		testDeterministic(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testCopyConstructor(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testAssignment(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testSerialization(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testFlattening(name, module);
	}

protected:
	static bool testEqualParams(Module<T> &m1, Module<T> &m2)
	{
		auto &p1 = m1.params();
		auto &p2 = m2.params();

		if(p1.shape() != p2.shape())
			return false;

		for(auto x = p1.begin(), y = p2.begin(), end = p1.end(); x != end; ++x, ++y)
		{
			if(std::abs(*x - *y) > 1e-12)
				return false;
		}

		return true;
	}

	static bool testNotShared(Module<T> &m1, Module<T> &m2)
	{
		return !m1.params().sharedWith(m2.params());
	}

	static bool testEqualOutput(Module<T> &m1, Module<T> &m2, const Tensor<T> &input)
	{
		RandomEngine::seed(0);
		m1.forget();
		auto &o1 = m1.forward(input);

		RandomEngine::seed(0);
		m2.forget();
		auto &o2 = m2.forward(input);

		for(auto x = o1.begin(), y = o2.begin(), end = o1.end(); x != end; ++x, ++y)
		{
			if(std::fabs(*x - *y) > 1e-12)
				return false;
		}

		return true;
	}

private:
	static void testDeterministic(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		RandomEngine::seed(0);
		module.forget();
		auto o1 = module.forward(input).copy();

		RandomEngine::seed(0);
		module.forget();
		auto o2 = module.forward(input).copy();

		for(auto x = o1.begin(), y = o2.begin(), end = o1.end(); x != end; ++x, ++y)
			NNAssertAlmostEquals(*x, *y, 1e-12, name + "::forward() failed! Different outputs for the same input and random seed!");
	}

	static void testCopyConstructor(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		module.params().rand();
		M<T> copy(module);
		NNAssert(testEqualParams(module, copy), name + "::" + name + "(const " + name + " &) failed! Parameters are not equal!");
		NNAssert(testNotShared(module, copy), name + "::" + name + "(const " + name + " &) failed! Sharing parameters; not a deep copy!");
		NNAssert(testEqualOutput(module, copy, input), name + "::" + name + "(const " + name + " &) failed! Different outputs for the same input!");
	}

	static void testAssignment(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		module.params().rand();

		M<T> copy(module);
		copy.params().fill(0);
		copy = module;

		NNAssert(testEqualParams(module, copy), name + "::operator=(const " + name + " &) failed! Parameters are not equal!");
		NNAssert(testNotShared(module, copy), name + "::operator=(const " + name + " &) failed! Sharing parameters; not a deep copy!");
		NNAssert(testEqualOutput(module, copy, input), name + "::operator=(const " + name + " &) failed! Different outputs for the same input!");

		// delete copy;
	}

	static void testSerialization(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		M<T> s1 = Serialized(module).as<M<T>>();
		NNAssert(testEqualParams(module, s1), "Serialization through reference failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, s1, input), "Serialization through reference failed! Different outputs for the same input!");

		M<T> s2 = Serialized(&module).as<M<T>>();
		NNAssert(testEqualParams(module, s2), "Serialization through pointer failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, s2, input), "Serialization through pointer failed! Different outputs for the same input!");

		Module<T> *s3 = Serialized(module).as<Module<T> *>();
		NNAssert(testEqualParams(module, *s3), "Generic serialization through reference failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, *s3, input), "Generic serialization through reference failed! Different outputs for the same input!");
		delete s3;

		Module<T> *s4 = Serialized(&module).as<Module<T> *>();
		NNAssert(testEqualParams(module, *s4), "Generic serialization through pointer failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, *s4, input), "Generic serialization through pointer failed! Different outputs for the same input!");
		delete s4;
	}

	static void testFlattening(const std::string &name, M<T> &module)
	{
		if(module.paramsList().size() > 0)
		{
			// flatten tensors
			auto &old = module.params();

			// intentionally break shared connection
			*module.paramsList()[0] = module.paramsList()[0]->copy();

			// intentionally add an extra shared connection
			auto view = old.view(0);

			// reflatten
			module.params();

			// ensure shared connection is back
			NNAssert(module.paramsList()[0]->sharedWith(module.params()), name + "::params() failed! Shared connections did not work correctly.");
		}

		if(module.gradList().size() > 0)
		{
			// flatten tensors
			auto &old = module.grad();

			// intentionally break shared connection
			*module.gradList()[0] = module.gradList()[0]->copy();

			// intentionally add an extra shared connection
			auto view = old.view(0);

			// reflatten
			module.grad();

			// ensure shared connection is back
			NNAssert(module.gradList()[0]->sharedWith(module.grad()), name + "::grad() failed! Shared connections did not work correctly.");
		}

		if(module.stateList().size() > 0)
		{
			// flatten tensors
			auto &old = module.state();

			// intentionally break shared connection
			*module.stateList()[0] = module.stateList()[0]->copy();

			// intentionally add an extra shared connection
			auto view = old.view(0);

			// reflatten
			module.state();

			// ensure shared connection is back
			NNAssert(module.stateList()[0]->sharedWith(module.state()), name + "::state() failed! Shared connections did not work correctly.");
		}
	}
};

template <template <typename> class M, typename T>
void TestModule(const std::string &name, M<T> &module, const Tensor<T> &input, bool randomizeInput = true)
{
	ModuleTests<M, T>::run(name, module, input, randomizeInput);
}

#endif
<commit_msg>Added unit test to make sure state works.<commit_after>#ifndef TEST_MODULE_H
#define TEST_MODULE_H

#include "nnlib/nn/module.hpp"
using namespace std;
using namespace nnlib;

template <template <typename> class M, typename T = double>
class ModuleTests
{
public:
	static void run(const std::string &name, M<T> &module, const Tensor<T> &sampleInput, bool randomizeInput = true)
	{
		testDeterministic(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testState(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testCopyConstructor(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testAssignment(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testSerialization(name, module, randomizeInput ? Tensor<T>(sampleInput.shape(), true).rand() : sampleInput);
		testFlattening(name, module);
	}

protected:
	static bool testEqualParams(Module<T> &m1, Module<T> &m2)
	{
		auto &p1 = m1.params();
		auto &p2 = m2.params();

		if(p1.shape() != p2.shape())
			return false;

		for(auto x = p1.begin(), y = p2.begin(), end = p1.end(); x != end; ++x, ++y)
		{
			if(std::abs(*x - *y) > 1e-12)
				return false;
		}

		return true;
	}

	static bool testNotShared(Module<T> &m1, Module<T> &m2)
	{
		return !m1.params().sharedWith(m2.params());
	}

	static bool testEqualOutput(Module<T> &m1, Module<T> &m2, const Tensor<T> &input)
	{
		RandomEngine::seed(0);
		m1.forget();
		auto &o1 = m1.forward(input);

		RandomEngine::seed(0);
		m2.forget();
		auto &o2 = m2.forward(input);

		for(auto x = o1.begin(), y = o2.begin(), end = o1.end(); x != end; ++x, ++y)
		{
			if(std::fabs(*x - *y) > 1e-12)
				return false;
		}

		return true;
	}

private:
	static void testDeterministic(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		RandomEngine::seed(0);
		module.forget();
		auto o1 = module.forward(input).copy();

		RandomEngine::seed(0);
		module.forget();
		auto o2 = module.forward(input).copy();

		for(auto x = o1.begin(), y = o2.begin(), end = o1.end(); x != end; ++x, ++y)
			NNAssertAlmostEquals(*x, *y, 1e-12, name + "::forward() failed! Different outputs for the same input and random seed!");
	}

	static void testState(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		RandomEngine::seed(0);
		auto s = module.state().copy();
		auto o1 = module.forward(input).copy();

		RandomEngine::seed(0);
		module.state().copy(s);
		auto o2 = module.forward(input);

		for(auto x = o1.begin(), y = o2.begin(), end = o1.end(); x != end; ++x, ++y)
			NNAssertAlmostEquals(*x, *y, 1e-12, name + "::state() failed! Different outputs for the same state and random seed!");
	}

	static void testCopyConstructor(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		module.params().rand();
		M<T> copy(module);
		NNAssert(testEqualParams(module, copy), name + "::" + name + "(const " + name + " &) failed! Parameters are not equal!");
		NNAssert(testNotShared(module, copy), name + "::" + name + "(const " + name + " &) failed! Sharing parameters; not a deep copy!");
		NNAssert(testEqualOutput(module, copy, input), name + "::" + name + "(const " + name + " &) failed! Different outputs for the same input!");
	}

	static void testAssignment(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		module.params().rand();

		M<T> copy(module);
		copy.params().fill(0);
		copy = module;

		NNAssert(testEqualParams(module, copy), name + "::operator=(const " + name + " &) failed! Parameters are not equal!");
		NNAssert(testNotShared(module, copy), name + "::operator=(const " + name + " &) failed! Sharing parameters; not a deep copy!");
		NNAssert(testEqualOutput(module, copy, input), name + "::operator=(const " + name + " &) failed! Different outputs for the same input!");

		// delete copy;
	}

	static void testSerialization(const std::string &name, M<T> &module, const Tensor<T> &input)
	{
		M<T> s1 = Serialized(module).as<M<T>>();
		NNAssert(testEqualParams(module, s1), "Serialization through reference failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, s1, input), "Serialization through reference failed! Different outputs for the same input!");

		M<T> s2 = Serialized(&module).as<M<T>>();
		NNAssert(testEqualParams(module, s2), "Serialization through pointer failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, s2, input), "Serialization through pointer failed! Different outputs for the same input!");

		Module<T> *s3 = Serialized(module).as<Module<T> *>();
		NNAssert(testEqualParams(module, *s3), "Generic serialization through reference failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, *s3, input), "Generic serialization through reference failed! Different outputs for the same input!");
		delete s3;

		Module<T> *s4 = Serialized(&module).as<Module<T> *>();
		NNAssert(testEqualParams(module, *s4), "Generic serialization through pointer failed! Parameters are not equal!");
		NNAssert(testEqualOutput(module, *s4, input), "Generic serialization through pointer failed! Different outputs for the same input!");
		delete s4;
	}

	static void testFlattening(const std::string &name, M<T> &module)
	{
		if(module.paramsList().size() > 0)
		{
			// flatten tensors
			auto &old = module.params();

			// intentionally break shared connection
			*module.paramsList()[0] = module.paramsList()[0]->copy();

			// intentionally add an extra shared connection
			auto view = old.view(0);

			// reflatten
			module.params();

			// ensure shared connection is back
			NNAssert(module.paramsList()[0]->sharedWith(module.params()), name + "::params() failed! Shared connections did not work correctly.");
		}

		if(module.gradList().size() > 0)
		{
			// flatten tensors
			auto &old = module.grad();

			// intentionally break shared connection
			*module.gradList()[0] = module.gradList()[0]->copy();

			// intentionally add an extra shared connection
			auto view = old.view(0);

			// reflatten
			module.grad();

			// ensure shared connection is back
			NNAssert(module.gradList()[0]->sharedWith(module.grad()), name + "::grad() failed! Shared connections did not work correctly.");
		}

		if(module.stateList().size() > 0)
		{
			// flatten tensors
			auto &old = module.state();

			// intentionally break shared connection
			*module.stateList()[0] = module.stateList()[0]->copy();

			// intentionally add an extra shared connection
			auto view = old.view(0);

			// reflatten
			module.state();

			// ensure shared connection is back
			NNAssert(module.stateList()[0]->sharedWith(module.state()), name + "::state() failed! Shared connections did not work correctly.");
		}
	}
};

template <template <typename> class M, typename T>
void TestModule(const std::string &name, M<T> &module, const Tensor<T> &input, bool randomizeInput = true)
{
	ModuleTests<M, T>::run(name, module, input, randomizeInput);
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved

// Author: Zhangyi Chen (chenzhangyi01@baidu.com)
// Date: 2017/11/06 10:57:08

#include "butil/popen.h"
#include "butil/errno.h"
#include "butil/strings/string_piece.h"
#include "butil/build_config.h"
#include <gtest/gtest.h>

namespace butil {
extern int read_command_output_through_clone(std::ostream&, const char*);
extern int read_command_output_through_popen(std::ostream&, const char*);
}

namespace {

class PopenTest : public testing::Test {
};

TEST(PopenTest, posix_popen) {
    std::ostringstream oss;
    int rc = butil::read_command_output_through_popen(oss, "echo \"Hello World\"");
    ASSERT_EQ(0, rc) << berror(errno);
    ASSERT_EQ("Hello World\n", oss.str());

    oss.str("");
    rc = butil::read_command_output_through_popen(oss, "exit 1");
    EXPECT_EQ(1, rc) << berror(errno);
    ASSERT_TRUE(oss.str().empty()) << oss;
    oss.str("");
    rc = butil::read_command_output_through_popen(oss, "kill -9 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "kill -15 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));

    oss.str("");
    ASSERT_EQ(0, butil::read_command_output_through_clone(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
    ASSERT_EQ(100000u, oss.str().length());
    std::string expected;
    expected.resize(100000, '=');
    ASSERT_EQ(expected, oss.str());
}

#if defined(OS_LINUX)

TEST(PopenTest, clone) {
    std::ostringstream oss;
    int rc = butil::read_command_output_through_clone(oss, "echo \"Hello World\"");
    ASSERT_EQ(0, rc) << berror(errno);
    ASSERT_EQ("Hello World\n", oss.str());

    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "exit 1");
    ASSERT_EQ(1, rc) << berror(errno);
    ASSERT_TRUE(oss.str().empty()) << oss;
    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "kill -9 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "kill -15 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));

    oss.str("");
    ASSERT_EQ(0, butil::read_command_output_through_clone(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
    ASSERT_EQ(100000u, oss.str().length());
    std::string expected;
    expected.resize(100000, '=');
    ASSERT_EQ(expected, oss.str());
}

struct CounterArg {
    volatile int64_t counter;
    volatile bool stop;
};

static void* counter_thread(void* args) {
    CounterArg* ca = (CounterArg*)args;
    while (!ca->stop) {
        ++ca->counter;
    }
    return NULL;
}

static int fork_thread(void* arg) {
    usleep(100 * 1000);
    _exit(0);
}

const int CHILD_STACK_SIZE = 64 * 1024;

TEST(PopenTest, does_vfork_suspend_all_threads) {
    pthread_t tid;
    CounterArg ca = { 0 , false };
    ASSERT_EQ(0, pthread_create(&tid, NULL, counter_thread, &ca));
    usleep(100 * 1000);
    char* child_stack_mem = (char*)malloc(CHILD_STACK_SIZE);
    void* child_stack = child_stack_mem + CHILD_STACK_SIZE;
    const int64_t counter_before_fork = ca.counter;
    pid_t cpid = clone(fork_thread, child_stack, CLONE_VFORK, NULL);
    const int64_t counter_after_fork = ca.counter;
    usleep(100 * 1000);
    const int64_t counter_after_sleep = ca.counter;
    int ws;
    ca.stop = true;
    pthread_join(tid, NULL);
    std::cout << "bc=" << counter_before_fork << " ac=" << counter_after_fork
              << " as=" << counter_after_sleep
              << std::endl;
    ASSERT_EQ(cpid, waitpid(cpid, &ws, __WALL));
}

#endif  // OS_LINUX

}
<commit_msg>fix test/popen_unittest.cpp<commit_after>// Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved

// Author: Zhangyi Chen (chenzhangyi01@baidu.com)
// Date: 2017/11/06 10:57:08

#include "butil/popen.h"
#include "butil/errno.h"
#include "butil/strings/string_piece.h"
#include "butil/build_config.h"
#include <gtest/gtest.h>

namespace butil {
extern int read_command_output_through_clone(std::ostream&, const char*);
extern int read_command_output_through_popen(std::ostream&, const char*);
}

namespace {

class PopenTest : public testing::Test {
};

TEST(PopenTest, posix_popen) {
    std::ostringstream oss;
    int rc = butil::read_command_output_through_popen(oss, "echo \"Hello World\"");
    ASSERT_EQ(0, rc) << berror(errno);
    ASSERT_EQ("Hello World\n", oss.str());

    oss.str("");
    rc = butil::read_command_output_through_popen(oss, "exit 1");
    EXPECT_EQ(1, rc) << berror(errno);
    ASSERT_TRUE(oss.str().empty()) << oss.str();
    oss.str("");
    rc = butil::read_command_output_through_popen(oss, "kill -9 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "kill -15 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));

    oss.str("");
    ASSERT_EQ(0, butil::read_command_output_through_clone(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
    ASSERT_EQ(100000u, oss.str().length());
    std::string expected;
    expected.resize(100000, '=');
    ASSERT_EQ(expected, oss.str());
}

#if defined(OS_LINUX)

TEST(PopenTest, clone) {
    std::ostringstream oss;
    int rc = butil::read_command_output_through_clone(oss, "echo \"Hello World\"");
    ASSERT_EQ(0, rc) << berror(errno);
    ASSERT_EQ("Hello World\n", oss.str());

    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "exit 1");
    ASSERT_EQ(1, rc) << berror(errno);
    ASSERT_TRUE(oss.str().empty()) << oss.str();
    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "kill -9 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
    oss.str("");
    rc = butil::read_command_output_through_clone(oss, "kill -15 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));

    oss.str("");
    ASSERT_EQ(0, butil::read_command_output_through_clone(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
    ASSERT_EQ(100000u, oss.str().length());
    std::string expected;
    expected.resize(100000, '=');
    ASSERT_EQ(expected, oss.str());
}

struct CounterArg {
    volatile int64_t counter;
    volatile bool stop;
};

static void* counter_thread(void* args) {
    CounterArg* ca = (CounterArg*)args;
    while (!ca->stop) {
        ++ca->counter;
    }
    return NULL;
}

static int fork_thread(void* arg) {
    usleep(100 * 1000);
    _exit(0);
}

const int CHILD_STACK_SIZE = 64 * 1024;

TEST(PopenTest, does_vfork_suspend_all_threads) {
    pthread_t tid;
    CounterArg ca = { 0 , false };
    ASSERT_EQ(0, pthread_create(&tid, NULL, counter_thread, &ca));
    usleep(100 * 1000);
    char* child_stack_mem = (char*)malloc(CHILD_STACK_SIZE);
    void* child_stack = child_stack_mem + CHILD_STACK_SIZE;
    const int64_t counter_before_fork = ca.counter;
    pid_t cpid = clone(fork_thread, child_stack, CLONE_VFORK, NULL);
    const int64_t counter_after_fork = ca.counter;
    usleep(100 * 1000);
    const int64_t counter_after_sleep = ca.counter;
    int ws;
    ca.stop = true;
    pthread_join(tid, NULL);
    std::cout << "bc=" << counter_before_fork << " ac=" << counter_after_fork
              << " as=" << counter_after_sleep
              << std::endl;
    ASSERT_EQ(cpid, waitpid(cpid, &ws, __WALL));
}

#endif  // OS_LINUX

}
<|endoftext|>


<commit_before>#include "sakutest.hpp"
#include "SurfaceLoader.hpp"

namespace sakutest{
using namespace cs454_2006;
void setup(data& d) {
	// Init libs
	db("Initialise SDL");
	nf(SDL_Init(SDL_INIT_VIDEO/*|SDL_INIT_AUDIO*/), "SDL Init");
	d.screen = SDL_SetVideoMode(
	 SCREEN_WIDTH,
	 SCREEN_HEIGHT,
	 SCREEN_BPP,
	 SCREEN_FLAGS
	);
	db("Initialise TTF");
	nf(TTF_Init(), "TTF Init");

	// Init paths
	d.animation_film_config_file_path = new std::string(
	 ANIMATION_FILM_CONFIG_FILE);
	d.animation_holder_config_file_path = new std::string(
	 ANIMATION_HOLDER_CONFIG_FILE);
	d.sprite_config_file_path = new std::string(
	 SPRITE_CONFIG_FILE);
	d.animation_setup_config_file_path = new std::string(
	 ANIMATION_SETUP_CONFIG_FILE);
	d.obstacle_platform_config_file_path = new std::string(
	 OBSTACLE_PLATFORM_CONFIG_FILE);
	d.waypoints_config_file_path = new std::string(
	 WAYPOINTS_CONFIG_FILE);

	// Timestamp
	d.startingTime = cs454_2006::getTimestamp();

	// create animations
	SetupData setup_d = {
		d.animation_film_config_file_path,
		d.animation_holder_config_file_path,
		d.sprite_config_file_path,
		d.obstacle_platform_config_file_path,
		d.waypoints_config_file_path
	};
	d.animation_data = setup_animations(&setup_d);
	// Set bug bitmap for junction visualisation
	d.animation_data->wayhold->setBug(SurfaceLoader::getInstance()->
	 loadSurface(*new std::string("./resources/animation_films/"
	 "waypoint.png")));

	// Fetch custom sprites
	d.pacman = dynamic_cast<GameSprite*>(
	 d.animation_data->spritehold->getSprite(1001));
	nf(!d.pacman, "Sprite 1001 must be pacman");

	// After move call
	d.amc = new after_move_call;

	// Custom animators
	d.animators = new __animators;
	d.animations = new __animations;
	d.yums = new __yums;
	d.yams = new __yams;
	//
	d.animators->pac = new MovingAnimator(false);
	d.animators->box = new MovingAnimator(false);
	d.animators->up = new MovingAnimator(false);
	d.animators->right = new MovingAnimator(false);
	d.animators->down = new MovingAnimator(false);
	d.animators->left = new MovingAnimator(false);
	d.animators->snaily[0] = new MovingAnimator(false);
	d.animators->snaily[1] = new MovingAnimator(false);
	d.animators->snaily[2] = new MovingAnimator(false);
	d.animators->snaily[3] = new MovingAnimator(false);
	//
	d.yums->u = new FrameRangeAnimator(false);
	d.yums->r = new FrameRangeAnimator(false);
	d.yums->d = new FrameRangeAnimator(false);
	d.yums->l = new FrameRangeAnimator(false);
	d.yums->snaily[0] = new FrameRangeAnimator(false);
	d.yums->snaily[1] = new FrameRangeAnimator(false);
	d.yums->snaily[2] = new FrameRangeAnimator(false);
	d.yums->snaily[3] = new FrameRangeAnimator(false);
	//
	// remove animators that must from holder
	AnimatorHolder::Cancel(d.animators->up);
	AnimatorHolder::Cancel(d.animators->right);
	AnimatorHolder::Cancel(d.animators->down);
	AnimatorHolder::Cancel(d.animators->left);
	//
	AnimatorHolder::Cancel(d.yums->u);
	AnimatorHolder::Cancel(d.yums->r);
	AnimatorHolder::Cancel(d.yums->l);
	AnimatorHolder::Cancel(d.yums->d);

	// custom animations
	//
	// Moving
	d.animations->up = d.animation_data->animhold->
	 getMovingAnimation(1002);
	d.animations->right = d.animation_data->animhold->
	 getMovingAnimation(1003);
	d.animations->down = d.animation_data->animhold->
	 getMovingAnimation(1004);
	d.animations->left = d.animation_data->animhold->
	 getMovingAnimation(1005);
	for (int i = 0; i < 4; i++)
		d.animations->snaily[i] = d.animation_data->animhold->
		 getMovingAnimation(3000 + i);
	// Frame range (yums)
	d.yams->u =d.animation_data->animhold->getFrameRangeAnimation(2005);
	d.yams->r =d.animation_data->animhold->getFrameRangeAnimation(2004);
	d.yams->l =d.animation_data->animhold->getFrameRangeAnimation(2003);
	d.yams->d =d.animation_data->animhold->getFrameRangeAnimation(2002);
	for (int i = 0; i < 4; i++)
		d.yams->snaily[i] = d.animation_data->animhold->
		 getFrameRangeAnimation(3004 + i);

	// Start animators
	d.animators->up->Start(d.pacman, d.animations->up, d.startingTime);
	d.animators->right->Start(d.pacman, d.animations->right, d.startingTime);
	d.animators->down->Start(d.pacman, d.animations->down, d.startingTime);
	d.animators->left->Start(d.pacman, d.animations->left, d.startingTime);
	d.yums->u->Start(d.pacman, d.yams->u, d.startingTime);
	d.yums->r->Start(d.pacman, d.yams->r, d.startingTime);
	d.yums->d->Start(d.pacman, d.yams->d, d.startingTime);
	d.yums->l->Start(d.pacman, d.yams->l, d.startingTime);
	//
	// For little snaily too
	for (int i = 0; i < 4; i++) {
		Sprite *snail;
		d.animators->snaily[i]->Start(snail = d.animation_data->
		 spritehold->getSprite(3003),
		 d.animations->snaily[i], d.startingTime);
		d.yums->snaily[i]->Start(snail, d.yams->snaily[i],
		 d.startingTime);
	}

	// create actor movement objects
	//
	// For pacman
	std::vector<MovingAnimator*> pacmovs;
	pacmovs.push_back(d.animators->up);
	pacmovs.push_back(d.animators->right);
	pacmovs.push_back(d.animators->down);
	pacmovs.push_back(d.animators->left);
	std::vector<FrameRangeAnimator*> yummovs;
	yummovs.push_back(d.yums->u);
	yummovs.push_back(d.yums->r);
	yummovs.push_back(d.yums->d);
	yummovs.push_back(d.yums->l);
	d.pacmov = new ActorMovement(d.pacman, pacmovs, yummovs, *d.amc,
	 d.startingTime);
	// For snaily
	std::vector<MovingAnimator*> snailymovs;
	std::vector<FrameRangeAnimator*> snailyyummovs;
	for (int i = 0; i < 4; i++) {
		snailymovs.push_back(d.animators->snaily[i]);
		snailyyummovs.push_back(d.yums->snaily[i]);
	}
	d.snailymov = new ActorMovement(dynamic_cast<Ghost*>(
	 d.animation_data->spritehold->
	 getSprite(3003)), snailymovs, snailyyummovs, *d.amc,
	 d.startingTime);

	// Set up AI
	Targets *targets = new Targets;
	targets->pacman = d.pacman;
	AI::SetTargets(targets);
	std::map<GameSprite*, ActorMovement*> actormoves;
	actormoves[d.pacman] = d.pacmov;
	actormoves[dynamic_cast<GameSprite*>(
	 d.animation_data->spritehold->getSprite(3003))] = d.snailymov;
	AI::SetMoves(actormoves);

	// register the above for collision checking
	setUpCollisions(d);

	// create the matcher for animtion starting
	d.matcher = new Matcher(d.animation_data->spritehold);
	start_animations(
	 d.animation_data->animhold,
	 d.matcher,
	 getTimestamp()
	);

	// create background colour for redrawing
	create_bgcolor(d);

	// set after move call
	AnimatorHolder::setAfterMoveCall(d.amc);

	// For handling input events
	//SDL_EnableKeyRepeat(10, 10);

	// Set up teleportation waypoints
	Waypoint* teleportals[] = {
		d.animation_data->wayhold->getWaypoint(666),
		d.animation_data->wayhold->getWaypoint(667)
	};
	for (int i = 0; i < 2; i++)
		teleportals[i]->SetCollisionCallback(
		 Waypoint::TeleportCallback,
		 teleportals[i == 0? 1 : 0]
		);
}
} // namespace sakutest

namespace cs454_2006 {
struct RegisterCollision :
 public std::binary_function<Sprite*, Sprite*, void>
{
	void operator() (Sprite* actor, Sprite* self) const;
};
struct setCustomCollisionCallback : public std::unary_function<Sprite*,void>
{
	void operator () (Sprite* obstacle);
	setCustomCollisionCallback(Sprite::CollisionCallback, void* c =
	 static_cast<void*>(0));
	private :
	Sprite::CollisionCallback cc;
	void *closure;
};
} // namespace cs45_2005

namespace sakutest {
void setUpCollisions(data& d) {
	SpriteHolder* sh;
	std::list<ObstacleSprite*> const& obstsps =
	 (sh = d.animation_data->spritehold)->getObstacleSprites();
	GameSprite *pacman, *box = NULL;
	ObstaclePlatformHolder::obstplats_map& plats =
	 d.animation_data->plathold->getObstaclePlatforms();

	nf(!(
	 ( pacman = dynamic_cast<GameSprite*>(sh->getSprite(1001)) ) &&
	 ( box    = dynamic_cast<GameSprite*>(sh->getSprite(1002)) ) ),
	 "Not a game sprite"
	);

	// Obstacles are registered by Platforms
	// ===
	// for each obstacle, add collision with those two
//	std::for_each(obstsps.begin(), obstsps.end(),
//	 std::bind1st(RegisterCollision(), pacman) );
//	std::for_each(obstsps.begin(), obstsps.end(),
//	 std::bind1st(RegisterCollision(), box) );

	// Ghost snail id-s
	std::list<int> ghostids;
	ghostids.push_back(3003);
	// Instead, register each pushable sprite with all platforms
	ObstaclePlatformHolder::obstplats_map::iterator ite;
	for (ite = plats.begin(); ite != plats.end(); ite++) {
		ite->second->SetCollisionCheck(pacman, true);
		ite->second->SetCollisionCheck(box, true);
		// for each ghost snail, register collision
		std::list<int>::const_iterator gite;
		for (gite = ghostids.begin();gite != ghostids.end();gite++){
			Ghost* g = dynamic_cast<Ghost*>(sh->getSprite(
			 *gite));
			nf(!g, "Sprite with 3003 <= id < 4000 is no a "
			 "ghost game sprite.");
			ite->second->SetCollisionCheck(g, true);
		}
	}

	// set up waypoint collisions with ghosts
	// TODO add all ghosts after testing is done
	Ghost* a_ghost = dynamic_cast<Ghost*>(sh->getSprite(3003));
	nf(!a_ghost, "Sprite with 3003 <= id < 4000 is no a "
	 "ghost game sprite.");
	std::list<Waypoint*> wps =
	 d.animation_data->wayhold->getWaypoints();
	std::list<Waypoint*>::iterator wite;
	for (wite = wps.begin(); wite != wps.end(); wite++)
		CollisionChecker::Singleton()->Register(*wite, a_ghost);

	// Set up pacman collision with two teleporters
	Waypoint* teleportals[] = {
		d.animation_data->wayhold->getWaypoint(666),
		d.animation_data->wayhold->getWaypoint(667)
	};
	for (int i =  0; i < 2; i++)
		CollisionChecker::Singleton()->Register(teleportals[i],
		 d.pacman);

	// set custom callback
	std::for_each(obstsps.begin(), obstsps.end(),
	 setCustomCollisionCallback(collision_callback, &d) );
}
} // namespace sakutest
void cs454_2006::RegisterCollision::operator () (Sprite* actor,
 Sprite* self) const
{
	CollisionChecker::Singleton()->Register(self, actor);
}

void cs454_2006::setCustomCollisionCallback::operator() (Sprite* obstacle) {
	obstacle->SetCollisionCallback(cc, closure);
}

cs454_2006::setCustomCollisionCallback::setCustomCollisionCallback(
 Sprite::CollisionCallback _cc, void* _closure) :
 cc(_cc), closure(_closure) { }
<commit_msg>Added targets for AI<commit_after>#include "sakutest.hpp"
#include "SurfaceLoader.hpp"

namespace sakutest{
using namespace cs454_2006;
void setup(data& d) {
	// Init libs
	db("Initialise SDL");
	nf(SDL_Init(SDL_INIT_VIDEO/*|SDL_INIT_AUDIO*/), "SDL Init");
	d.screen = SDL_SetVideoMode(
	 SCREEN_WIDTH,
	 SCREEN_HEIGHT,
	 SCREEN_BPP,
	 SCREEN_FLAGS
	);
	db("Initialise TTF");
	nf(TTF_Init(), "TTF Init");

	// Init paths
	d.animation_film_config_file_path = new std::string(
	 ANIMATION_FILM_CONFIG_FILE);
	d.animation_holder_config_file_path = new std::string(
	 ANIMATION_HOLDER_CONFIG_FILE);
	d.sprite_config_file_path = new std::string(
	 SPRITE_CONFIG_FILE);
	d.animation_setup_config_file_path = new std::string(
	 ANIMATION_SETUP_CONFIG_FILE);
	d.obstacle_platform_config_file_path = new std::string(
	 OBSTACLE_PLATFORM_CONFIG_FILE);
	d.waypoints_config_file_path = new std::string(
	 WAYPOINTS_CONFIG_FILE);

	// Timestamp
	d.startingTime = cs454_2006::getTimestamp();

	// create animations
	SetupData setup_d = {
		d.animation_film_config_file_path,
		d.animation_holder_config_file_path,
		d.sprite_config_file_path,
		d.obstacle_platform_config_file_path,
		d.waypoints_config_file_path
	};
	d.animation_data = setup_animations(&setup_d);
	// Set bug bitmap for junction visualisation
	d.animation_data->wayhold->setBug(SurfaceLoader::getInstance()->
	 loadSurface(*new std::string("./resources/animation_films/"
	 "waypoint.png")));

	// Fetch custom sprites
	d.pacman = dynamic_cast<GameSprite*>(
	 d.animation_data->spritehold->getSprite(1001));
	nf(!d.pacman, "Sprite 1001 must be pacman");

	// After move call
	d.amc = new after_move_call;

	// Custom animators
	d.animators = new __animators;
	d.animations = new __animations;
	d.yums = new __yums;
	d.yams = new __yams;
	//
	d.animators->pac = new MovingAnimator(false);
	d.animators->box = new MovingAnimator(false);
	d.animators->up = new MovingAnimator(false);
	d.animators->right = new MovingAnimator(false);
	d.animators->down = new MovingAnimator(false);
	d.animators->left = new MovingAnimator(false);
	d.animators->snaily[0] = new MovingAnimator(false);
	d.animators->snaily[1] = new MovingAnimator(false);
	d.animators->snaily[2] = new MovingAnimator(false);
	d.animators->snaily[3] = new MovingAnimator(false);
	//
	d.yums->u = new FrameRangeAnimator(false);
	d.yums->r = new FrameRangeAnimator(false);
	d.yums->d = new FrameRangeAnimator(false);
	d.yums->l = new FrameRangeAnimator(false);
	d.yums->snaily[0] = new FrameRangeAnimator(false);
	d.yums->snaily[1] = new FrameRangeAnimator(false);
	d.yums->snaily[2] = new FrameRangeAnimator(false);
	d.yums->snaily[3] = new FrameRangeAnimator(false);
	//
	// remove animators that must from holder
	AnimatorHolder::Cancel(d.animators->up);
	AnimatorHolder::Cancel(d.animators->right);
	AnimatorHolder::Cancel(d.animators->down);
	AnimatorHolder::Cancel(d.animators->left);
	//
	AnimatorHolder::Cancel(d.yums->u);
	AnimatorHolder::Cancel(d.yums->r);
	AnimatorHolder::Cancel(d.yums->l);
	AnimatorHolder::Cancel(d.yums->d);

	// custom animations
	//
	// Moving
	d.animations->up = d.animation_data->animhold->
	 getMovingAnimation(1002);
	d.animations->right = d.animation_data->animhold->
	 getMovingAnimation(1003);
	d.animations->down = d.animation_data->animhold->
	 getMovingAnimation(1004);
	d.animations->left = d.animation_data->animhold->
	 getMovingAnimation(1005);
	for (int i = 0; i < 4; i++)
		d.animations->snaily[i] = d.animation_data->animhold->
		 getMovingAnimation(3000 + i);
	// Frame range (yums)
	d.yams->u =d.animation_data->animhold->getFrameRangeAnimation(2005);
	d.yams->r =d.animation_data->animhold->getFrameRangeAnimation(2004);
	d.yams->l =d.animation_data->animhold->getFrameRangeAnimation(2003);
	d.yams->d =d.animation_data->animhold->getFrameRangeAnimation(2002);
	for (int i = 0; i < 4; i++)
		d.yams->snaily[i] = d.animation_data->animhold->
		 getFrameRangeAnimation(3004 + i);

	// Start animators
	d.animators->up->Start(d.pacman, d.animations->up, d.startingTime);
	d.animators->right->Start(d.pacman, d.animations->right, d.startingTime);
	d.animators->down->Start(d.pacman, d.animations->down, d.startingTime);
	d.animators->left->Start(d.pacman, d.animations->left, d.startingTime);
	d.yums->u->Start(d.pacman, d.yams->u, d.startingTime);
	d.yums->r->Start(d.pacman, d.yams->r, d.startingTime);
	d.yums->d->Start(d.pacman, d.yams->d, d.startingTime);
	d.yums->l->Start(d.pacman, d.yams->l, d.startingTime);
	//
	// For little snaily too
	for (int i = 0; i < 4; i++) {
		Sprite *snail;
		d.animators->snaily[i]->Start(snail = d.animation_data->
		 spritehold->getSprite(3003),
		 d.animations->snaily[i], d.startingTime);
		d.yums->snaily[i]->Start(snail, d.yams->snaily[i],
		 d.startingTime);
	}

	// create actor movement objects
	//
	// For pacman
	std::vector<MovingAnimator*> pacmovs;
	pacmovs.push_back(d.animators->up);
	pacmovs.push_back(d.animators->right);
	pacmovs.push_back(d.animators->down);
	pacmovs.push_back(d.animators->left);
	std::vector<FrameRangeAnimator*> yummovs;
	yummovs.push_back(d.yums->u);
	yummovs.push_back(d.yums->r);
	yummovs.push_back(d.yums->d);
	yummovs.push_back(d.yums->l);
	d.pacmov = new ActorMovement(d.pacman, pacmovs, yummovs, *d.amc,
	 d.startingTime);
	// For snaily
	std::vector<MovingAnimator*> snailymovs;
	std::vector<FrameRangeAnimator*> snailyyummovs;
	for (int i = 0; i < 4; i++) {
		snailymovs.push_back(d.animators->snaily[i]);
		snailyyummovs.push_back(d.yums->snaily[i]);
	}
	d.snailymov = new ActorMovement(dynamic_cast<Ghost*>(
	 d.animation_data->spritehold->
	 getSprite(3003)), snailymovs, snailyyummovs, *d.amc,
	 d.startingTime);

	// Set up AI
	Targets *targets = new Targets;
	targets->pacman = d.pacman;
	targets->lair = d.animation_data->wayhold->getWaypoint(802);
	AI::SetTargets(targets);
	std::map<GameSprite*, ActorMovement*> actormoves;
	actormoves[d.pacman] = d.pacmov;
	actormoves[dynamic_cast<GameSprite*>(
	 d.animation_data->spritehold->getSprite(3003))] = d.snailymov;
	AI::SetMoves(actormoves);

	// register the above for collision checking
	setUpCollisions(d);

	// create the matcher for animtion starting
	d.matcher = new Matcher(d.animation_data->spritehold);
	start_animations(
	 d.animation_data->animhold,
	 d.matcher,
	 getTimestamp()
	);

	// create background colour for redrawing
	create_bgcolor(d);

	// set after move call
	AnimatorHolder::setAfterMoveCall(d.amc);

	// For handling input events
	//SDL_EnableKeyRepeat(10, 10);

	// Set up teleportation waypoints
	Waypoint* teleportals[] = {
		d.animation_data->wayhold->getWaypoint(666),
		d.animation_data->wayhold->getWaypoint(667)
	};
	for (int i = 0; i < 2; i++)
		teleportals[i]->SetCollisionCallback(
		 Waypoint::TeleportCallback,
		 teleportals[i == 0? 1 : 0]
		);

	// Set up targets for AI
}
} // namespace sakutest

namespace cs454_2006 {
struct RegisterCollision :
 public std::binary_function<Sprite*, Sprite*, void>
{
	void operator() (Sprite* actor, Sprite* self) const;
};
struct setCustomCollisionCallback : public std::unary_function<Sprite*,void>
{
	void operator () (Sprite* obstacle);
	setCustomCollisionCallback(Sprite::CollisionCallback, void* c =
	 static_cast<void*>(0));
	private :
	Sprite::CollisionCallback cc;
	void *closure;
};
} // namespace cs45_2005

namespace sakutest {
void setUpCollisions(data& d) {
	SpriteHolder* sh;
	std::list<ObstacleSprite*> const& obstsps =
	 (sh = d.animation_data->spritehold)->getObstacleSprites();
	GameSprite *pacman, *box = NULL;
	ObstaclePlatformHolder::obstplats_map& plats =
	 d.animation_data->plathold->getObstaclePlatforms();

	nf(!(
	 ( pacman = dynamic_cast<GameSprite*>(sh->getSprite(1001)) ) &&
	 ( box    = dynamic_cast<GameSprite*>(sh->getSprite(1002)) ) ),
	 "Not a game sprite"
	);

	// Obstacles are registered by Platforms
	// ===
	// for each obstacle, add collision with those two
//	std::for_each(obstsps.begin(), obstsps.end(),
//	 std::bind1st(RegisterCollision(), pacman) );
//	std::for_each(obstsps.begin(), obstsps.end(),
//	 std::bind1st(RegisterCollision(), box) );

	// Ghost snail id-s
	std::list<int> ghostids;
	ghostids.push_back(3003);
	// Instead, register each pushable sprite with all platforms
	ObstaclePlatformHolder::obstplats_map::iterator ite;
	for (ite = plats.begin(); ite != plats.end(); ite++) {
		ite->second->SetCollisionCheck(pacman, true);
		ite->second->SetCollisionCheck(box, true);
		// for each ghost snail, register collision
		std::list<int>::const_iterator gite;
		for (gite = ghostids.begin();gite != ghostids.end();gite++){
			Ghost* g = dynamic_cast<Ghost*>(sh->getSprite(
			 *gite));
			nf(!g, "Sprite with 3003 <= id < 4000 is no a "
			 "ghost game sprite.");
			ite->second->SetCollisionCheck(g, true);
		}
	}

	// set up waypoint collisions with ghosts
	// TODO add all ghosts after testing is done
	Ghost* a_ghost = dynamic_cast<Ghost*>(sh->getSprite(3003));
	nf(!a_ghost, "Sprite with 3003 <= id < 4000 is no a "
	 "ghost game sprite.");
	std::list<Waypoint*> wps =
	 d.animation_data->wayhold->getWaypoints();
	std::list<Waypoint*>::iterator wite;
	for (wite = wps.begin(); wite != wps.end(); wite++)
		CollisionChecker::Singleton()->Register(*wite, a_ghost);

	// Set up pacman collision with two teleporters
	Waypoint* teleportals[] = {
		d.animation_data->wayhold->getWaypoint(666),
		d.animation_data->wayhold->getWaypoint(667)
	};
	for (int i =  0; i < 2; i++)
		CollisionChecker::Singleton()->Register(teleportals[i],
		 d.pacman);

	// set custom callback
	std::for_each(obstsps.begin(), obstsps.end(),
	 setCustomCollisionCallback(collision_callback, &d) );
}
} // namespace sakutest
void cs454_2006::RegisterCollision::operator () (Sprite* actor,
 Sprite* self) const
{
	CollisionChecker::Singleton()->Register(self, actor);
}

void cs454_2006::setCustomCollisionCallback::operator() (Sprite* obstacle) {
	obstacle->SetCollisionCallback(cc, closure);
}

cs454_2006::setCustomCollisionCallback::setCustomCollisionCallback(
 Sprite::CollisionCallback _cc, void* _closure) :
 cc(_cc), closure(_closure) { }
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/create_torrent.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name
	, bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		if (peer_disconnected_alert* p = dynamic_cast<peer_disconnected_alert*>(a.get()))
		{
			std::cerr << name << "(" << p->ip << "): " << p->message() << "\n";
		}
		else if (a->message() != "block downloading"
			&& a->message() != "block finished"
			&& a->message() != "piece finished")
		{
			std::cerr << name << ": " << a->message() << "\n";
		}
		TEST_CHECK(dynamic_cast<fastresume_rejected_alert*>(a.get()) == 0 || allow_failed_fastresume);

		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->message() == "connecting to peer"
			|| a->message() == "closing connection to ourself"
			|| a->message() == "duplicate connection"
			|| a->message() == "duplicate peer-id, connection closed"
			|| (allow_disconnects && a->message() == "Broken pipe")
			|| (allow_disconnects && a->message() == "Connection reset by peer")
			|| (allow_disconnects && a->message() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port, bool ssl)
{
	stop_web_server(port);

	if (ssl)
	{
		system("echo . > tmp");
		system("echo test province >>tmp");
		system("echo test city >> tmp");
		system("echo test company >> tmp");
		system("echo test department >> tmp");
		system("echo tester >> tmp");
		system("echo test@test.com >> tmp");
		system("openssl req -new -x509 -keyout server.pem -out server.pem "
			"-days 365 -nodes <tmp");
	}

	std::ofstream f("lighty_config");
	f << "server.modules = (\"mod_access\", \"mod_redirect\", \"mod_setenv\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n"
		"url.redirect = ("
			"\"^/redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/test_file\""
			", \"^/infinite_redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\""
			", \"^/relative/redirect$\" => \"../test_file\""
			")\n"
		"$HTTP[\"url\"] == \"/test_file.gz\" {\n"
		"    setenv.add-response-header = ( \"Content-Encoding\" => \"gzip\" )\n"
		"#    mimetype.assign = ()\n"
		"}\n";
	// this requires lighttpd to be built with ssl support.
	// The port distribution for mac is not built with ssl
	// support by default.
	if (ssl)
		f << "ssl.engine = \"enable\"\n"
			"ssl.pemfile = \"server.pem\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com "
		"PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
	test_sleep(1000);
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size, int num_pieces)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	file_storage fs;
	int total_size = piece_size * num_pieces;
	fs.add_file(path("temporary"), total_size);
	libtorrent::create_torrent t(fs, piece_size);
	t.add_tracker(tracker_url);

	std::vector<char> piece(piece_size);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t.num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t.set_hash(i, ph);

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	std::vector<char> tmp;
	std::back_insert_iterator<std::vector<char> > out(tmp);
	bencode(out, t.generate());
	return boost::intrusive_ptr<torrent_info>(new torrent_info(&tmp[0], tmp.size()));
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix, int piece_size
	, boost::intrusive_ptr<torrent_info>* torrent)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	assert(ses1->id() != ses2->id());
	if (ses3)
		assert(ses3->id() != ses2->id());

	boost::intrusive_ptr<torrent_info> t;
	if (torrent == 0)
	{
		create_directory("./tmp1" + suffix);
		std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
		t = ::create_torrent(&file, piece_size, 1024 / 8);
		file.close();
		if (clear_files)
		{
			remove_all("./tmp2" + suffix + "/temporary");
			remove_all("./tmp3" + suffix + "/temporary");
		}
		std::cerr << "generated torrent: " << t->info_hash() << std::endl;
	}
	else
	{
		t = *torrent;
	}

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<commit_msg>fixed setup transfer for the test<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/create_torrent.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name
	, bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		if (peer_disconnected_alert* p = dynamic_cast<peer_disconnected_alert*>(a.get()))
		{
			std::cerr << name << "(" << p->ip << "): " << p->message() << "\n";
		}
		else if (a->message() != "block downloading"
			&& a->message() != "block finished"
			&& a->message() != "piece finished")
		{
			std::cerr << name << ": " << a->message() << "\n";
		}
		TEST_CHECK(dynamic_cast<fastresume_rejected_alert*>(a.get()) == 0 || allow_failed_fastresume);

		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->message() == "connecting to peer"
			|| a->message() == "closing connection to ourself"
			|| a->message() == "duplicate connection"
			|| a->message() == "duplicate peer-id, connection closed"
			|| (allow_disconnects && a->message() == "Broken pipe")
			|| (allow_disconnects && a->message() == "Connection reset by peer")
			|| (allow_disconnects && a->message() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port, bool ssl)
{
	stop_web_server(port);

	if (ssl)
	{
		system("echo . > tmp");
		system("echo test province >>tmp");
		system("echo test city >> tmp");
		system("echo test company >> tmp");
		system("echo test department >> tmp");
		system("echo tester >> tmp");
		system("echo test@test.com >> tmp");
		system("openssl req -new -x509 -keyout server.pem -out server.pem "
			"-days 365 -nodes <tmp");
	}

	std::ofstream f("lighty_config");
	f << "server.modules = (\"mod_access\", \"mod_redirect\", \"mod_setenv\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n"
		"url.redirect = ("
			"\"^/redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/test_file\""
			", \"^/infinite_redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\""
			", \"^/relative/redirect$\" => \"../test_file\""
			")\n"
		"$HTTP[\"url\"] == \"/test_file.gz\" {\n"
		"    setenv.add-response-header = ( \"Content-Encoding\" => \"gzip\" )\n"
		"#    mimetype.assign = ()\n"
		"}\n";
	// this requires lighttpd to be built with ssl support.
	// The port distribution for mac is not built with ssl
	// support by default.
	if (ssl)
		f << "ssl.engine = \"enable\"\n"
			"ssl.pemfile = \"server.pem\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com "
		"PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
	test_sleep(1000);
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size, int num_pieces)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	file_storage fs;
	int total_size = piece_size * num_pieces;
	fs.add_file(path("temporary"), total_size);
	libtorrent::create_torrent t(fs, piece_size);
	t.add_tracker(tracker_url);

	std::vector<char> piece(piece_size);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t.num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t.set_hash(i, ph);

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	std::vector<char> tmp;
	std::back_insert_iterator<std::vector<char> > out(tmp);
	bencode(out, t.generate());
	return boost::intrusive_ptr<torrent_info>(new torrent_info(&tmp[0], tmp.size()));
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix, int piece_size
	, boost::intrusive_ptr<torrent_info>* torrent)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	std::srand(time(0));
	peer_id pid;
	std::generate(&pid[0], &pid[0] + 20, std::rand);
	ses1->set_peer_id(pid);
	std::generate(&pid[0], &pid[0] + 20, std::rand);
	ses2->set_peer_id(pid);
	assert(ses1->id() != ses2->id());
	if (ses3)
	{
		std::generate(&pid[0], &pid[0] + 20, std::rand);
		ses3->set_peer_id(pid);
		assert(ses3->id() != ses2->id());
	}

	boost::intrusive_ptr<torrent_info> t;
	if (torrent == 0)
	{
		create_directory("./tmp1" + suffix);
		std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
		t = ::create_torrent(&file, piece_size, 1024 / 8);
		file.close();
		if (clear_files)
		{
			remove_all("./tmp2" + suffix + "/temporary");
			remove_all("./tmp3" + suffix + "/temporary");
		}
		std::cerr << "generated torrent: " << t->info_hash() << std::endl;
	}
	else
	{
		t = *torrent;
	}

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<|endoftext|>


<commit_before>#include "medida/stats/ckms.h"
#include <gtest/gtest.h>
#include <algorithm>
#include <random>

using namespace medida::stats;

TEST(CKMSTest, aCKMSAddHundredOnes) {
  std::vector<CKMS::Quantile> v({{0.5, 0.001}, {0.99, 0.001}, {1, 0}});
  auto ckms = CKMS(v);
  for (int i = 0; i < 100; i++) {
      ckms.insert(1);
  }
  EXPECT_NEAR(1, ckms.get(0.5), 1e-6);
  EXPECT_NEAR(1, ckms.get(0.99), 1e-6);
  EXPECT_NEAR(1, ckms.get(1), 1e-6);
}

TEST(CKMSTest, aCKMSAddOneToHundredThounsand) {
  // 0.1% error
  //
  // E.g., when guessing P99, it returns a value between
  // - P(1 - 0.001) * 99 = P98.901, and
  // - P(1 + 0.001) * 99 = P99.099
  //
  // See the definition of \epsilon-approximate in
  // http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf
  double const error = 0.001;

  auto const percentiles = {0.5, 0.75, 0.9, 0.99};
  std::vector<CKMS::Quantile> v;
  v.reserve(percentiles.size());
  for (auto const q: percentiles) {
    v.push_back({q, error});
  }

  auto ckms = CKMS(v);

  int const count = 100 * 1000;
  for (int i = 1; i <= count; i++) {
      ckms.insert(i);
  }

  for (auto const q: percentiles) {
      EXPECT_LE((1 - error) * q * count, ckms.get(q));
      EXPECT_GE((1 + error) * q * count, ckms.get(q));
  }
}

TEST(CKMSTest, aCKMSUniform) {
  double const error = 0.001;
  auto const percentiles = {0.5, 0.75, 0.9, 0.99};
  std::vector<CKMS::Quantile> v;
  v.reserve(percentiles.size());
  for (auto const q: percentiles) {
    v.push_back({q, error});
  }

  auto ckms = CKMS(v);

  srand(time(NULL));
  int const count = 100 * 1000;
  std::vector<int> values;
  values.reserve(count);
  for (int i = 1; i <= count; i++) {
      auto x = rand();
      values.push_back(x);
      ckms.insert(x);
  }

  std::sort(values.begin(), values.end());
  for (auto const q: percentiles) {
      EXPECT_LE(values[int((1 - error) * q * count)], ckms.get(q));
      EXPECT_GE(values[int((1 + error) * q * count)], ckms.get(q));
  }
}

TEST(CKMSTest, aCKMSGamma) {
  double const error = 0.001;
  auto const percentiles = {0.5, 0.75, 0.9, 0.99};
  std::vector<CKMS::Quantile> v;
  v.reserve(percentiles.size());
  for (auto const q: percentiles) {
    v.push_back({q, error});
  }

  auto ckms = CKMS(v);

  int const count = 100 * 1000;
  std::vector<double> values;
  values.reserve(count);

  // 0 = seed
  std::mt19937 gen(0);

  // A gamma distribution with alpha=20, and beta=100
  // gives a bell curve with the top ~2000 between ~800 and ~400.
  std::gamma_distribution<double> d(20, 100);
  for (int i = 0; i < count; i++) {
      auto x = d(gen);
      values.push_back(x);
      ckms.insert(x);
  }

  std::sort(values.begin(), values.end());
  for (auto const q: percentiles) {
      EXPECT_LE(values[int((1 - error) * q * count)], ckms.get(q));
      EXPECT_GE(values[int((1 + error) * q * count)], ckms.get(q));
  }
}
<commit_msg>Test CKMS when the sample size is small. It fails as expected.<commit_after>#include "medida/stats/ckms.h"
#include <gtest/gtest.h>
#include <algorithm>
#include <random>

using namespace medida::stats;

TEST(CKMSTest, aCKMSAddHundredOnes) {
  std::vector<CKMS::Quantile> v({{0.5, 0.001}, {0.99, 0.001}, {1, 0}});
  auto ckms = CKMS(v);
  for (int i = 0; i < 100; i++) {
      ckms.insert(1);
  }
  EXPECT_NEAR(1, ckms.get(0.5), 1e-6);
  EXPECT_NEAR(1, ckms.get(0.99), 1e-6);
  EXPECT_NEAR(1, ckms.get(1), 1e-6);
}

TEST(CKMSTest, aCKMSSmallSampleSizes) {
  std::vector<int> sizes({3, 10});
  std::vector<double> percentiles({0.5, 0.75, 0.99, 0.999});
  for (auto const size : sizes) {
      {
        // Add {1, 2, ..., size}
        std::vector<CKMS::Quantile> v({{0.5, 0.001}, {0.99, 0.001}, {1, 0}});
        auto ckms = CKMS(v);
        for (int i = 1; i <= size; i++) {
            ckms.insert(i);
        }
        for (auto const percentile : percentiles) {
            // x is the q-th percentile if and only if
            // x is the smallest number such that at least q% of all samples are <= x.
            // In this case, the sample is {1, 2, ..., size}, so it's easy to calculate.
            auto want = ceil(size * percentile);
            EXPECT_NEAR(want, ckms.get(percentile), 1e-6);
        }
      }
      {
        // Add {size, size - 1, ..., 1}
        std::vector<CKMS::Quantile> v({{0.5, 0.001}, {0.99, 0.001}, {1, 0}});
        auto ckms = CKMS(v);
        for (int i = size; i >= 1; i--) {
            ckms.insert(i);
        }
        for (auto const percentile : percentiles) {
            // x is the q-th percentile if and only if
            // x is the smallest number such that at least q% of all samples are <= x.
            // In this case, the sample is {1, 2, ..., size}, so it's easy to calculate.
            auto want = ceil(size * percentile);
            EXPECT_NEAR(want, ckms.get(percentile), 1e-6);
        }
      }
  }
}

TEST(CKMSTest, aCKMSExactToApprox) {
  std::vector<double> percentiles({0.5, 0.75, 0.99, 0.999});
  // Make sure that CKMS returns the correct result when size = 499.
  // This is because CKMS is supposed to hold up to 499 elements
  // and sort when reporting.
  const int size = 499;
  std::vector<CKMS::Quantile> v({{0.5, 0.001}, {0.99, 0.001}, {1, 0}});
  auto ckms = CKMS(v);
  for (int i = 1; i <= size; i++) {
      ckms.insert(i);
  }
  for (auto const percentile : percentiles) {
      // x is the q-th percentile if and only if
      // x is the smallest number such that at least q% of all samples are <= x.
      // In this case, the sample is {1, 2, ..., size}, so it's easy to calculate.
      auto want = ceil(size * percentile);
      EXPECT_NEAR(want, ckms.get(percentile), 1e-6);
  }

  // Now we'll insert the 500th element.
  // CKMS switches to an approximation as the buffer is now full.
  ckms.insert(500);
  for (auto const percentile : percentiles) {
      auto want = ceil(500 * percentile);
      // When there are 500 elements,
      // the absolute difference of 2 is 0.4%.
      // e.g., Instead of P99.9, CKMS might report
      // P99.5 which is really close.
      EXPECT_NEAR(want, ckms.get(percentile), 2);
  }
}

TEST(CKMSTest, aCKMSAddOneToHundredThounsand) {
  // 0.1% error
  //
  // E.g., when guessing P99, it returns a value between
  // - P(1 - 0.001) * 99 = P98.901, and
  // - P(1 + 0.001) * 99 = P99.099
  //
  // See the definition of \epsilon-approximate in
  // http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf
  double const error = 0.001;

  auto const percentiles = {0.5, 0.75, 0.9, 0.99};
  std::vector<CKMS::Quantile> v;
  v.reserve(percentiles.size());
  for (auto const q: percentiles) {
    v.push_back({q, error});
  }

  auto ckms = CKMS(v);

  int const count = 100 * 1000;
  for (int i = 1; i <= count; i++) {
      ckms.insert(i);
  }

  for (auto const q: percentiles) {
      EXPECT_LE((1 - error) * q * count, ckms.get(q));
      EXPECT_GE((1 + error) * q * count, ckms.get(q));
  }
}

TEST(CKMSTest, aCKMSUniform) {
  double const error = 0.001;
  auto const percentiles = {0.5, 0.75, 0.9, 0.99};
  std::vector<CKMS::Quantile> v;
  v.reserve(percentiles.size());
  for (auto const q: percentiles) {
    v.push_back({q, error});
  }

  auto ckms = CKMS(v);

  srand(time(NULL));
  int const count = 100 * 1000;
  std::vector<int> values;
  values.reserve(count);
  for (int i = 1; i <= count; i++) {
      auto x = rand();
      values.push_back(x);
      ckms.insert(x);
  }

  std::sort(values.begin(), values.end());
  for (auto const q: percentiles) {
      EXPECT_LE(values[int((1 - error) * q * count)], ckms.get(q));
      EXPECT_GE(values[int((1 + error) * q * count)], ckms.get(q));
  }
}

TEST(CKMSTest, aCKMSGamma) {
  double const error = 0.001;
  auto const percentiles = {0.5, 0.75, 0.9, 0.99};
  std::vector<CKMS::Quantile> v;
  v.reserve(percentiles.size());
  for (auto const q: percentiles) {
    v.push_back({q, error});
  }

  auto ckms = CKMS(v);

  int const count = 100 * 1000;
  std::vector<double> values;
  values.reserve(count);

  // 0 = seed
  std::mt19937 gen(0);

  // A gamma distribution with alpha=20, and beta=100
  // gives a bell curve with the top ~2000 between ~800 and ~400.
  std::gamma_distribution<double> d(20, 100);
  for (int i = 0; i < count; i++) {
      auto x = d(gen);
      values.push_back(x);
      ckms.insert(x);
  }

  std::sort(values.begin(), values.end());
  for (auto const q: percentiles) {
      EXPECT_LE(values[int((1 - error) * q * count)], ckms.get(q));
      EXPECT_GE(values[int((1 + error) * q * count)], ckms.get(q));
  }
}
<|endoftext|>


<commit_before>#include "P4Objects.h"
#include "behavioral_utils/json.h"
#include <iostream>

void P4Objects::init_objects(std::istream &is) {
  Json::Value cfg_root;
  is >> cfg_root;

  header_type_id_t header_type_id = 0;

  // header types

  const Json::Value cfg_header_types = cfg_root["header_types"];
  for (const auto &cfg_header_type : cfg_header_types) {
    const string header_type_name = cfg_header_type["name"].asString();
    HeaderType *header_type = new HeaderType(header_type_id++,
					     header_type_name);
    add_header_type(header_type_name, header_type);

    const Json::Value cfg_fields = cfg_header_type["fields"];
    for (auto it = cfg_fields.begin(); it != cfg_fields.end(); it++) {
      const string field_name = it.key().asString();
      int field_bit_width = (*it).asInt();
      header_type->push_back_field(field_name, field_bit_width);
    }
  }

  // headers

  const Json::Value cfg_headers = cfg_root["headers"];
  for (const auto &cfg_header : cfg_headers) {

    const string header_name = cfg_header["name"].asString();
    const string header_type_name = cfg_header["header_type"].asString();

    HeaderType *header_type = get_header_type(header_type_name);

    header_id_t header_id = phv.push_back_header(header_name, *header_type);
    add_header_id(header_name, header_id);
  }

  // parsers

  const Json::Value cfg_parsers = cfg_root["parsers"];
  for (const auto &cfg_parser : cfg_parsers) {

    const string parser_name = cfg_parser["name"].asString();

    Parser *parser = new Parser();
    add_parser(parser_name, parser);

    unordered_map<string, ParseState *> current_parse_states;

    // parse states

    const Json::Value cfg_parse_states = cfg_parser["parse_states"];
    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = new ParseState(parse_state_name);

      const Json::Value cfg_extracts = cfg_parse_state["extracts"];
      for(const auto &cfg_extract : cfg_extracts) {
	const string header_name = cfg_extract.asString();
	header_id_t header_id = get_header_id(header_name);
	parse_state->add_extract(header_id);
      }

      // we do not support parser set ops for now

      ParseSwitchKeyBuilder key_builder;
      const Json::Value cfg_transition_key = cfg_parse_state["transition_key"];
      for (const auto &cfg_key_field : cfg_transition_key) {

	const string header_name = cfg_key_field[0].asString();
	const string field_name = cfg_key_field[1].asString();
	header_id_t header_id = get_header_id(header_name);
	const HeaderType &header_type =
	  phv.get_header(header_id).get_header_type();
	int field_offset = header_type.get_field_offset(field_name);
	key_builder.push_back_field(header_id, field_offset);
      }

      parse_state->set_key_builder(key_builder);

      parse_states.push_back(parse_state);
      current_parse_states[parse_state_name] = parse_state;
    }

    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = current_parse_states[parse_state_name];
      const Json::Value cfg_transitions = cfg_parse_state["transitions"];
      for(const auto &cfg_transition : cfg_transitions) {

      	const string value_hexstr = cfg_transition["value"].asString();
      	// ignore mask for now
	const string next_state_name = cfg_transition["next_state"].asString();
      	const ParseState *next_state = current_parse_states[next_state_name];
	ByteContainer c(9);
	parse_state->add_switch_case(c, next_state);
      }
    }

    const string init_state_name = cfg_parser["init_state"].asString();
    const ParseState *init_state = current_parse_states[init_state_name];
    parser->set_init_state(init_state);
  }

  // deparsers

  const Json::Value cfg_deparsers = cfg_root["deparsers"];
  for (const auto &cfg_deparser : cfg_deparsers) {

    const string deparser_name = cfg_deparser["name"].asString();
    Deparser *deparser = new Deparser();
    add_deparser(deparser_name, deparser);

    const Json::Value cfg_ordered_headers = cfg_deparser["order"];
    for (const auto &cfg_header : cfg_ordered_headers) {

      const string header_name = cfg_header.asString();
      deparser->push_back_header(get_header_id(header_name));
    }
  }
}

/* use unique pointers to get rid of this code ?, it is not really important
   anyway, this is config only, and is only allocated once */

void P4Objects::destroy_objects() {
  for(auto it = header_types_map.begin(); it != header_types_map.end(); ++it)
    delete it->second;
  for(auto it = exact_tables_map.begin(); it != exact_tables_map.end(); ++it)
    delete it->second;
  for(auto it = lpm_tables_map.begin(); it != lpm_tables_map.end(); ++it)
    delete it->second;
  for(auto it = ternary_tables_map.begin(); it != ternary_tables_map.end(); ++it)
    delete it->second;
  for(auto it = parsers.begin(); it != parsers.end(); ++it)
    delete it->second;
  for(auto it = deparsers.begin(); it != deparsers.end(); ++it)
    delete it->second;
  for(auto it : parse_states)
    delete it;
}
<commit_msg>forgot a small change<commit_after>#include "P4Objects.h"
#include "behavioral_utils/json.h"
#include <iostream>

void P4Objects::init_objects(std::istream &is) {
  Json::Value cfg_root;
  is >> cfg_root;

  header_type_id_t header_type_id = 0;

  // header types

  const Json::Value cfg_header_types = cfg_root["header_types"];
  for (const auto &cfg_header_type : cfg_header_types) {
    const string header_type_name = cfg_header_type["name"].asString();
    HeaderType *header_type = new HeaderType(header_type_id++,
					     header_type_name);
    add_header_type(header_type_name, header_type);

    const Json::Value cfg_fields = cfg_header_type["fields"];
    for (auto it = cfg_fields.begin(); it != cfg_fields.end(); it++) {
      const string field_name = it.key().asString();
      int field_bit_width = (*it).asInt();
      header_type->push_back_field(field_name, field_bit_width);
    }
  }

  // headers

  const Json::Value cfg_headers = cfg_root["headers"];
  for (const auto &cfg_header : cfg_headers) {

    const string header_name = cfg_header["name"].asString();
    const string header_type_name = cfg_header["header_type"].asString();

    HeaderType *header_type = get_header_type(header_type_name);

    header_id_t header_id = phv.push_back_header(header_name, *header_type);
    add_header_id(header_name, header_id);
  }

  // parsers

  const Json::Value cfg_parsers = cfg_root["parsers"];
  for (const auto &cfg_parser : cfg_parsers) {

    const string parser_name = cfg_parser["name"].asString();

    Parser *parser = new Parser();
    add_parser(parser_name, parser);

    unordered_map<string, ParseState *> current_parse_states;

    // parse states

    const Json::Value cfg_parse_states = cfg_parser["parse_states"];
    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = new ParseState(parse_state_name);

      const Json::Value cfg_extracts = cfg_parse_state["extracts"];
      for(const auto &cfg_extract : cfg_extracts) {
	const string header_name = cfg_extract.asString();
	header_id_t header_id = get_header_id(header_name);
	parse_state->add_extract(header_id);
      }

      // we do not support parser set ops for now

      ParseSwitchKeyBuilder key_builder;
      const Json::Value cfg_transition_key = cfg_parse_state["transition_key"];
      for (const auto &cfg_key_field : cfg_transition_key) {

	const string header_name = cfg_key_field[0].asString();
	const string field_name = cfg_key_field[1].asString();
	header_id_t header_id = get_header_id(header_name);
	const HeaderType &header_type =
	  phv.get_header(header_id).get_header_type();
	int field_offset = header_type.get_field_offset(field_name);
	key_builder.push_back_field(header_id, field_offset);
      }

      parse_state->set_key_builder(key_builder);

      parse_states.push_back(parse_state);
      current_parse_states[parse_state_name] = parse_state;
    }

    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = current_parse_states[parse_state_name];
      const Json::Value cfg_transitions = cfg_parse_state["transitions"];
      for(const auto &cfg_transition : cfg_transitions) {

      	const string value_hexstr = cfg_transition["value"].asString();
      	// ignore mask for now
	const string next_state_name = cfg_transition["next_state"].asString();
      	const ParseState *next_state = current_parse_states[next_state_name];
	parse_state->add_switch_case(ByteContainer(value_hexstr),
				     next_state);
      }
    }

    const string init_state_name = cfg_parser["init_state"].asString();
    const ParseState *init_state = current_parse_states[init_state_name];
    parser->set_init_state(init_state);
  }

  // deparsers

  const Json::Value cfg_deparsers = cfg_root["deparsers"];
  for (const auto &cfg_deparser : cfg_deparsers) {

    const string deparser_name = cfg_deparser["name"].asString();
    Deparser *deparser = new Deparser();
    add_deparser(deparser_name, deparser);

    const Json::Value cfg_ordered_headers = cfg_deparser["order"];
    for (const auto &cfg_header : cfg_ordered_headers) {

      const string header_name = cfg_header.asString();
      deparser->push_back_header(get_header_id(header_name));
    }
  }
}

/* use unique pointers to get rid of this code ?, it is not really important
   anyway, this is config only, and is only allocated once */

void P4Objects::destroy_objects() {
  for(auto it = header_types_map.begin(); it != header_types_map.end(); ++it)
    delete it->second;
  for(auto it = exact_tables_map.begin(); it != exact_tables_map.end(); ++it)
    delete it->second;
  for(auto it = lpm_tables_map.begin(); it != lpm_tables_map.end(); ++it)
    delete it->second;
  for(auto it = ternary_tables_map.begin(); it != ternary_tables_map.end(); ++it)
    delete it->second;
  for(auto it = parsers.begin(); it != parsers.end(); ++it)
    delete it->second;
  for(auto it = deparsers.begin(); it != deparsers.end(); ++it)
    delete it->second;
  for(auto it : parse_states)
    delete it;
}
<|endoftext|>


<commit_before>/****************************************************************/
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*          All contents are licensed under LGPL V2.1           */
/*             See LICENSE for full restrictions                */
/****************************************************************/
#include "INSMomentum.h"

template<>
InputParameters validParams<INSMomentum>()
{
  InputParameters params = validParams<Kernel>();

  // Coupled variables
  params.addRequiredCoupledVar("u", "x-velocity");
  params.addCoupledVar("v", 0, "y-velocity"); // only required in 2D and 3D
  params.addCoupledVar("w", 0, "z-velocity"); // only required in 3D
  params.addRequiredCoupledVar("p", "pressure");

  // Required parameters
  params.addRequiredParam<Real>("mu", "dynamic viscosity");
  params.addRequiredParam<Real>("rho", "density");
  params.addRequiredParam<RealVectorValue>("gravity", "Direction of the gravity vector");
  params.addRequiredParam<unsigned>("component", "0,1,2 depending on if we are solving the x,y,z component of the momentum equation");
  params.addParam<bool>("integrate_p_by_parts", true, "Allows simulations to be run with pressure BC if set to false");

  MooseEnum coord_types("XYZ RZ RSPHERICAL");
  params.addParam<MooseEnum>("coord_type", coord_types, "Coordinate system types. Choices are: " + coord_types.getRawNames());
  return params;
}

INSMomentum::INSMomentum(const InputParameters & parameters) :
  Kernel(parameters),

  _coord_type_set(false),

  // Coupled variables
  _u_vel(coupledValue("u")),
  _v_vel(coupledValue("v")),
  _w_vel(coupledValue("w")),
  _p(coupledValue("p")),

  // Gradients
  _grad_u_vel(coupledGradient("u")),
  _grad_v_vel(coupledGradient("v")),
  _grad_w_vel(coupledGradient("w")),
  _grad_p(coupledGradient("p")),

  // Variable numberings
  _u_vel_var_number(coupled("u")),
  _v_vel_var_number(coupled("v")),
  _w_vel_var_number(coupled("w")),
  _p_var_number(coupled("p")),

  // Required parameters
  _mu(getParam<Real>("mu")),
  _rho(getParam<Real>("rho")),
  _gravity(getParam<RealVectorValue>("gravity")),
  _component(getParam<unsigned>("component")),
  _integrate_p_by_parts(getParam<bool>("integrate_p_by_parts"))

  // Material properties
  // _dynamic_viscosity(getMaterialProperty<Real>("dynamic_viscosity"))
{
}

void INSMomentum::setGeometryParameter(const InputParameters & params,
                                    INSMomentum::COORD_TYPE & coord_type)
{
  if (params.isParamSetByUser("coord_type"))
  {
    coord_type = INSMomentum::COORD_TYPE(int(params.get<MooseEnum>("coord_type")));
  }
  else
  {
    coord_type = INSMomentum::XYZ;
  }
}

void INSMomentum::computeResidual()
{
  if (!_coord_type_set)
  {
    setGeometryParameter(_pars, _coord_type);
    _coord_type_set = true;
  }

  Kernel::computeResidual();
}

Real INSMomentum::computeQpResidual()
{
  // We need this for RZ kernels.
  const Real r = _q_point[_qp](0);

  // The convection part, rho * (u.grad) * u_component * v.
  // Note: _grad_u is the gradient of the _component entry of the velocity vector.
  Real convective_part = _rho *
    (_u_vel[_qp]*_grad_u[_qp](0) +
     _v_vel[_qp]*_grad_u[_qp](1) +
     _w_vel[_qp]*_grad_u[_qp](2)) * _test[_i][_qp];

  // The pressure part, -p (div v) or (dp/dx_{component}) * test if not integrated by parts.
  Real pressure_part = 0.;
  if (_integrate_p_by_parts)
  {
    pressure_part = -_p[_qp] * _grad_test[_i][_qp](_component);
    if (_coord_type == INSMomentum::RZ && _component == 0)
      pressure_part += -_p[_qp] / r * _test[_i][_qp];
  }
  else
    pressure_part = _grad_p[_qp](_component) * _test[_i][_qp];

  // The component'th row (or col, it's symmetric) of the viscous stress tensor
  RealVectorValue tau_row;

  switch (_component)
  {
  case 0:
    tau_row(0) = 2.*_grad_u_vel[_qp](0);                    // 2*du/dx1
    tau_row(1) = _grad_u_vel[_qp](1) + _grad_v_vel[_qp](0); // du/dx2 + dv/dx1
    tau_row(2) = _grad_u_vel[_qp](2) + _grad_w_vel[_qp](0); // du/dx3 + dw/dx1
    break;

  case 1:
    tau_row(0) = _grad_v_vel[_qp](0) + _grad_u_vel[_qp](1); // dv/dx1 + du/dx2
    tau_row(1) = 2.*_grad_v_vel[_qp](1);                    // 2*dv/dx2
    tau_row(2) = _grad_v_vel[_qp](2) + _grad_w_vel[_qp](1); // dv/dx3 + dw/dx2
    break;

  case 2:
    tau_row(0) = _grad_w_vel[_qp](0) + _grad_u_vel[_qp](2); // dw/dx1 + du/dx3
    tau_row(1) = _grad_w_vel[_qp](1) + _grad_v_vel[_qp](2); // dw/dx2 + dv/dx3
    tau_row(2) = 2.*_grad_w_vel[_qp](2);                    // 2*dw/dx3
    break;

  default:
    mooseError("Unrecognized _component requested.");
  }

  // The viscous part, tau : grad(v)
  Real viscous_part = _mu * (tau_row * _grad_test[_i][_qp]);
  if (_coord_type == INSMomentum::RZ && _component == 0)
    viscous_part += 2. * _u_vel[_qp] * _test[_i][_qp] / (r*r);

  // Simplified version: mu * Laplacian(u_component)
  // Real viscous_part = _mu * (_grad_u[_qp] * _grad_test[_i][_qp]);

  // Body force term.  For truly incompressible flow, this term is constant, and
  // since it is proportional to g, can be written as the gradient of some scalar
  // and absorbed into the pressure definition.
  // Real body_force_part = - _rho * _gravity(_component);

  return convective_part + pressure_part + viscous_part /*+ body_force_part*/;
}

Real INSMomentum::computeQpJacobian()
{
  // We need this for RZ kernels.
  const Real r = _q_point[_qp](0);

  RealVectorValue U(_u_vel[_qp], _v_vel[_qp], _w_vel[_qp]);

  // Convective part
  Real convective_part = _rho * ((U*_grad_phi[_j][_qp]) + _phi[_j][_qp]*_grad_u[_qp](_component)) * _test[_i][_qp];

  // Viscous part, Stokes/Laplacian version
  // Real viscous_part = _mu * (_grad_phi[_j][_qp] * _grad_test[_i][_qp]);

  // Viscous part, full stress tensor.  The extra contribution comes from the "2"
  // on the diagonal of the viscous stress tensor.
  Real viscous_part = _mu * (_grad_phi[_j][_qp]             * _grad_test[_i][_qp] +
                             _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](_component));
  if (_coord_type == INSMomentum::RZ && _component == 0)
    viscous_part += 2. * _phi[_j][_qp] * _test[_i][_qp] / (r*r);

  return convective_part + viscous_part;
}

Real INSMomentum::computeQpOffDiagJacobian(unsigned jvar)
{
  // We need this for RZ kernels.
  const Real r = _q_point[_qp](0);

  // In Stokes/Laplacian version, off-diag Jacobian entries wrt u,v,w are zero
  if (jvar == _u_vel_var_number)
  {
    Real convective_part = _phi[_j][_qp] * _grad_u[_qp](0) * _test[_i][_qp];
    Real viscous_part = _mu * _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](0);

    return convective_part + viscous_part;
  }

  else if (jvar == _v_vel_var_number)
  {
    Real convective_part = _phi[_j][_qp] * _grad_u[_qp](1) * _test[_i][_qp];
    Real viscous_part = _mu * _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](1);

    return convective_part + viscous_part;
  }

  else if (jvar == _w_vel_var_number)
  {
    Real convective_part = _phi[_j][_qp] * _grad_u[_qp](2) * _test[_i][_qp];
    Real viscous_part = _mu * _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](2);

    return convective_part + viscous_part;
  }

  else if (jvar == _p_var_number)
  {
    if (_integrate_p_by_parts)
    {
      Real pressure_part = -_phi[_j][_qp] * _grad_test[_i][_qp](_component);
      if (_coord_type == INSMomentum::RZ && _component == 0)
        pressure_part += -_phi[_j][_qp] / r * _test[_i][_qp];
      return pressure_part;
    }
    else
      return _grad_phi[_j][_qp](_component) * _test[_i][_qp];
  }

  else
    return 0;
}
<commit_msg>Forgot a _mu on the extra term in residual and Jacobian.<commit_after>/****************************************************************/
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*          All contents are licensed under LGPL V2.1           */
/*             See LICENSE for full restrictions                */
/****************************************************************/
#include "INSMomentum.h"

template<>
InputParameters validParams<INSMomentum>()
{
  InputParameters params = validParams<Kernel>();

  // Coupled variables
  params.addRequiredCoupledVar("u", "x-velocity");
  params.addCoupledVar("v", 0, "y-velocity"); // only required in 2D and 3D
  params.addCoupledVar("w", 0, "z-velocity"); // only required in 3D
  params.addRequiredCoupledVar("p", "pressure");

  // Required parameters
  params.addRequiredParam<Real>("mu", "dynamic viscosity");
  params.addRequiredParam<Real>("rho", "density");
  params.addRequiredParam<RealVectorValue>("gravity", "Direction of the gravity vector");
  params.addRequiredParam<unsigned>("component", "0,1,2 depending on if we are solving the x,y,z component of the momentum equation");
  params.addParam<bool>("integrate_p_by_parts", true, "Allows simulations to be run with pressure BC if set to false");

  MooseEnum coord_types("XYZ RZ RSPHERICAL");
  params.addParam<MooseEnum>("coord_type", coord_types, "Coordinate system types. Choices are: " + coord_types.getRawNames());
  return params;
}

INSMomentum::INSMomentum(const InputParameters & parameters) :
  Kernel(parameters),

  _coord_type_set(false),

  // Coupled variables
  _u_vel(coupledValue("u")),
  _v_vel(coupledValue("v")),
  _w_vel(coupledValue("w")),
  _p(coupledValue("p")),

  // Gradients
  _grad_u_vel(coupledGradient("u")),
  _grad_v_vel(coupledGradient("v")),
  _grad_w_vel(coupledGradient("w")),
  _grad_p(coupledGradient("p")),

  // Variable numberings
  _u_vel_var_number(coupled("u")),
  _v_vel_var_number(coupled("v")),
  _w_vel_var_number(coupled("w")),
  _p_var_number(coupled("p")),

  // Required parameters
  _mu(getParam<Real>("mu")),
  _rho(getParam<Real>("rho")),
  _gravity(getParam<RealVectorValue>("gravity")),
  _component(getParam<unsigned>("component")),
  _integrate_p_by_parts(getParam<bool>("integrate_p_by_parts"))

  // Material properties
  // _dynamic_viscosity(getMaterialProperty<Real>("dynamic_viscosity"))
{
}

void INSMomentum::setGeometryParameter(const InputParameters & params,
                                    INSMomentum::COORD_TYPE & coord_type)
{
  if (params.isParamSetByUser("coord_type"))
  {
    coord_type = INSMomentum::COORD_TYPE(int(params.get<MooseEnum>("coord_type")));
  }
  else
  {
    coord_type = INSMomentum::XYZ;
  }
}

void INSMomentum::computeResidual()
{
  if (!_coord_type_set)
  {
    setGeometryParameter(_pars, _coord_type);
    _coord_type_set = true;
  }

  Kernel::computeResidual();
}

Real INSMomentum::computeQpResidual()
{
  // We need this for RZ kernels.
  const Real r = _q_point[_qp](0);

  // The convection part, rho * (u.grad) * u_component * v.
  // Note: _grad_u is the gradient of the _component entry of the velocity vector.
  Real convective_part = _rho *
    (_u_vel[_qp]*_grad_u[_qp](0) +
     _v_vel[_qp]*_grad_u[_qp](1) +
     _w_vel[_qp]*_grad_u[_qp](2)) * _test[_i][_qp];

  // The pressure part, -p (div v) or (dp/dx_{component}) * test if not integrated by parts.
  Real pressure_part = 0.;
  if (_integrate_p_by_parts)
  {
    pressure_part = -_p[_qp] * _grad_test[_i][_qp](_component);
    if (_coord_type == INSMomentum::RZ && _component == 0)
      pressure_part += -_p[_qp] / r * _test[_i][_qp];
  }
  else
    pressure_part = _grad_p[_qp](_component) * _test[_i][_qp];

  // The component'th row (or col, it's symmetric) of the viscous stress tensor
  RealVectorValue tau_row;

  switch (_component)
  {
  case 0:
    tau_row(0) = 2.*_grad_u_vel[_qp](0);                    // 2*du/dx1
    tau_row(1) = _grad_u_vel[_qp](1) + _grad_v_vel[_qp](0); // du/dx2 + dv/dx1
    tau_row(2) = _grad_u_vel[_qp](2) + _grad_w_vel[_qp](0); // du/dx3 + dw/dx1
    break;

  case 1:
    tau_row(0) = _grad_v_vel[_qp](0) + _grad_u_vel[_qp](1); // dv/dx1 + du/dx2
    tau_row(1) = 2.*_grad_v_vel[_qp](1);                    // 2*dv/dx2
    tau_row(2) = _grad_v_vel[_qp](2) + _grad_w_vel[_qp](1); // dv/dx3 + dw/dx2
    break;

  case 2:
    tau_row(0) = _grad_w_vel[_qp](0) + _grad_u_vel[_qp](2); // dw/dx1 + du/dx3
    tau_row(1) = _grad_w_vel[_qp](1) + _grad_v_vel[_qp](2); // dw/dx2 + dv/dx3
    tau_row(2) = 2.*_grad_w_vel[_qp](2);                    // 2*dw/dx3
    break;

  default:
    mooseError("Unrecognized _component requested.");
  }

  // The viscous part, tau : grad(v)
  Real viscous_part = _mu * (tau_row * _grad_test[_i][_qp]);
  if (_coord_type == INSMomentum::RZ && _component == 0)
    viscous_part += 2. * _mu * _u_vel[_qp] * _test[_i][_qp] / (r*r);

  // Simplified version: mu * Laplacian(u_component)
  // Real viscous_part = _mu * (_grad_u[_qp] * _grad_test[_i][_qp]);

  // Body force term.  For truly incompressible flow, this term is constant, and
  // since it is proportional to g, can be written as the gradient of some scalar
  // and absorbed into the pressure definition.
  // Real body_force_part = - _rho * _gravity(_component);

  return convective_part + pressure_part + viscous_part /*+ body_force_part*/;
}

Real INSMomentum::computeQpJacobian()
{
  // We need this for RZ kernels.
  const Real r = _q_point[_qp](0);

  RealVectorValue U(_u_vel[_qp], _v_vel[_qp], _w_vel[_qp]);

  // Convective part
  Real convective_part = _rho * ((U*_grad_phi[_j][_qp]) + _phi[_j][_qp]*_grad_u[_qp](_component)) * _test[_i][_qp];

  // Viscous part, Stokes/Laplacian version
  // Real viscous_part = _mu * (_grad_phi[_j][_qp] * _grad_test[_i][_qp]);

  // Viscous part, full stress tensor.  The extra contribution comes from the "2"
  // on the diagonal of the viscous stress tensor.
  Real viscous_part = _mu * (_grad_phi[_j][_qp]             * _grad_test[_i][_qp] +
                             _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](_component));
  if (_coord_type == INSMomentum::RZ && _component == 0)
    viscous_part += 2. * _mu * _phi[_j][_qp] * _test[_i][_qp] / (r*r);

  return convective_part + viscous_part;
}

Real INSMomentum::computeQpOffDiagJacobian(unsigned jvar)
{
  // We need this for RZ kernels.
  const Real r = _q_point[_qp](0);

  // In Stokes/Laplacian version, off-diag Jacobian entries wrt u,v,w are zero
  if (jvar == _u_vel_var_number)
  {
    Real convective_part = _phi[_j][_qp] * _grad_u[_qp](0) * _test[_i][_qp];
    Real viscous_part = _mu * _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](0);

    return convective_part + viscous_part;
  }

  else if (jvar == _v_vel_var_number)
  {
    Real convective_part = _phi[_j][_qp] * _grad_u[_qp](1) * _test[_i][_qp];
    Real viscous_part = _mu * _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](1);

    return convective_part + viscous_part;
  }

  else if (jvar == _w_vel_var_number)
  {
    Real convective_part = _phi[_j][_qp] * _grad_u[_qp](2) * _test[_i][_qp];
    Real viscous_part = _mu * _grad_phi[_j][_qp](_component) * _grad_test[_i][_qp](2);

    return convective_part + viscous_part;
  }

  else if (jvar == _p_var_number)
  {
    if (_integrate_p_by_parts)
    {
      Real pressure_part = -_phi[_j][_qp] * _grad_test[_i][_qp](_component);
      if (_coord_type == INSMomentum::RZ && _component == 0)
        pressure_part += -_phi[_j][_qp] / r * _test[_i][_qp];
      return pressure_part;
    }
    else
      return _grad_phi[_j][_qp](_component) * _test[_i][_qp];
  }

  else
    return 0;
}
<|endoftext|>