<commit_before>/*
 *    Copyright (c) 2022 Project CHIP Authors
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <protocols/secure_channel/DefaultSessionResumptionStorage.h>

#include <lib/support/Base64.h>
#include <lib/support/SafeInt.h>

namespace chip {

CHIP_ERROR DefaultSessionResumptionStorage::FindByScopedNodeId(const ScopedNodeId & node, ResumptionIdStorage & resumptionId,
                                                               Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
{
    ReturnErrorOnFailure(LoadState(node, resumptionId, sharedSecret, peerCATs));
    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::FindByResumptionId(ConstResumptionIdView resumptionId, ScopedNodeId & node,
                                                               Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
{
    ReturnErrorOnFailure(FindNodeByResumptionId(resumptionId, node));
    ResumptionIdStorage tmpResumptionId;
    ReturnErrorOnFailure(FindByScopedNodeId(node, tmpResumptionId, sharedSecret, peerCATs));
    VerifyOrReturnError(std::equal(tmpResumptionId.begin(), tmpResumptionId.end(), resumptionId.begin(), resumptionId.end()),
                        CHIP_ERROR_KEY_NOT_FOUND);
    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::FindNodeByResumptionId(ConstResumptionIdView resumptionId, ScopedNodeId & node)
{
    ReturnErrorOnFailure(LoadLink(resumptionId, node));
    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::Save(const ScopedNodeId & node, ConstResumptionIdView resumptionId,
                                                 const Crypto::P256ECDHDerivedSecret & sharedSecret, const CATValues & peerCATs)
{
    SessionIndex index;
    ReturnErrorOnFailure(LoadIndex(index));

    if (index.mSize == CHIP_CONFIG_CASE_SESSION_RESUME_CACHE_SIZE)
    {
        // TODO: implement LRU for resumption
        ReturnErrorOnFailure(Delete(index.mNodes[0]));
        ReturnErrorOnFailure(LoadIndex(index));
    }

    ReturnErrorOnFailure(SaveState(node, resumptionId, sharedSecret, peerCATs));
    ReturnErrorOnFailure(SaveLink(resumptionId, node));

    index.mNodes[index.mSize++] = node;
    ReturnErrorOnFailure(SaveIndex(index));

    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::Delete(const ScopedNodeId & node)
{
    SessionIndex index;
    ReturnErrorOnFailure(LoadIndex(index));

    ResumptionIdStorage resumptionId;
    Crypto::P256ECDHDerivedSecret sharedSecret;
    CATValues peerCATs;
    CHIP_ERROR err = LoadState(node, resumptionId, sharedSecret, peerCATs);
    if (err == CHIP_NO_ERROR)
    {
        err = DeleteLink(resumptionId);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Unable to delete session resumption link for node " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
                         ChipLogValueX64(node.GetNodeId()), err.Format());
        }
    }
    else
    {
        ChipLogError(SecureChannel,
                     "Unable to load session resumption state during session deletion for node " ChipLogFormatX64
                     ": %" CHIP_ERROR_FORMAT,
                     ChipLogValueX64(node.GetNodeId()), err.Format());
    }

    err = DeleteState(node);
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(SecureChannel, "Unable to delete session resumption state for node " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
                     ChipLogValueX64(node.GetNodeId()), err.Format());
    }

    bool found = false;
    for (size_t i = 0; i < index.mSize; ++i)
    {
        if (found)
        {
            // index.mSize was decreased by 1 when found was set to true.
            // So the (i+1)th element isn't out of bounds.
            index.mNodes[i] = index.mNodes[i + 1];
        }
        else
        {
            if (index.mNodes[i] == node)
            {
                found = true;
                if (i + 1 < index.mSize)
                {
                    index.mNodes[i] = index.mNodes[i + 1];
                }
                index.mSize -= 1;
            }
        }
    }

    if (found)
    {
        err = SaveIndex(index);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel, "Unable to save session resumption index: %" CHIP_ERROR_FORMAT, err.Format());
        }
    }
    else
    {
        ChipLogError(SecureChannel,
                     "Unable to find session resumption state for node in index" ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
                     ChipLogValueX64(node.GetNodeId()), err.Format());
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::DeleteAll(FabricIndex fabricIndex)
{
    CHIP_ERROR stickyErr = CHIP_NO_ERROR;
    size_t found         = 0;
    SessionIndex index;
    ReturnErrorOnFailure(LoadIndex(index));
    size_t initialSize = index.mSize;
    for (size_t i = 0; i < initialSize; ++i)
    {
        CHIP_ERROR err = CHIP_NO_ERROR;
        size_t cur     = i - found;
        size_t remain  = initialSize - i;
        ResumptionIdStorage resumptionId;
        Crypto::P256ECDHDerivedSecret sharedSecret;
        CATValues peerCATs;
        if (index.mNodes[cur].GetFabricIndex() != fabricIndex)
        {
            continue;
        }
        err       = LoadState(index.mNodes[cur], resumptionId, sharedSecret, peerCATs);
        stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Session resumption cache deletion partially failed for fabric index %u, "
                         "unable to load node state: %" CHIP_ERROR_FORMAT,
                         fabricIndex, err.Format());
            continue;
        }
        err       = DeleteLink(resumptionId);
        stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Session resumption cache deletion partially failed for fabric index %u, "
                         "unable to delete node link: %" CHIP_ERROR_FORMAT,
                         fabricIndex, err.Format());
            continue;
        }
        err       = DeleteState(index.mNodes[cur]);
        stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Session resumption cache is in an inconsistent state!  "
                         "Unable to delete node state during attempted deletion of fabric index %u: %" CHIP_ERROR_FORMAT,
                         fabricIndex, err.Format());
            continue;
        }
        ++found;
        --remain;
        if (remain)
        {
            memmove(&index.mNodes[cur], &index.mNodes[cur + 1], remain * sizeof(index.mNodes[0]));
        }
    }
    if (found)
    {
        index.mSize -= found;
        CHIP_ERROR err = SaveIndex(index);
        stickyErr      = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(
                SecureChannel,
                "Session resumption cache is in an inconsistent state!  "
                "Unable to save session resumption index during atetmpted deletion of fabric index %u: %" CHIP_ERROR_FORMAT,
                fabricIndex, err.Format());
        }
    }
    return stickyErr;
}

} // namespace chip
<commit_msg>CASE resumption: fix incorrect error log messages (#18902)<commit_after>/*
 *    Copyright (c) 2022 Project CHIP Authors
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <protocols/secure_channel/DefaultSessionResumptionStorage.h>

#include <lib/support/Base64.h>
#include <lib/support/SafeInt.h>

namespace chip {

CHIP_ERROR DefaultSessionResumptionStorage::FindByScopedNodeId(const ScopedNodeId & node, ResumptionIdStorage & resumptionId,
                                                               Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
{
    ReturnErrorOnFailure(LoadState(node, resumptionId, sharedSecret, peerCATs));
    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::FindByResumptionId(ConstResumptionIdView resumptionId, ScopedNodeId & node,
                                                               Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
{
    ReturnErrorOnFailure(FindNodeByResumptionId(resumptionId, node));
    ResumptionIdStorage tmpResumptionId;
    ReturnErrorOnFailure(FindByScopedNodeId(node, tmpResumptionId, sharedSecret, peerCATs));
    VerifyOrReturnError(std::equal(tmpResumptionId.begin(), tmpResumptionId.end(), resumptionId.begin(), resumptionId.end()),
                        CHIP_ERROR_KEY_NOT_FOUND);
    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::FindNodeByResumptionId(ConstResumptionIdView resumptionId, ScopedNodeId & node)
{
    ReturnErrorOnFailure(LoadLink(resumptionId, node));
    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::Save(const ScopedNodeId & node, ConstResumptionIdView resumptionId,
                                                 const Crypto::P256ECDHDerivedSecret & sharedSecret, const CATValues & peerCATs)
{
    SessionIndex index;
    ReturnErrorOnFailure(LoadIndex(index));

    if (index.mSize == CHIP_CONFIG_CASE_SESSION_RESUME_CACHE_SIZE)
    {
        // TODO: implement LRU for resumption
        ReturnErrorOnFailure(Delete(index.mNodes[0]));
        ReturnErrorOnFailure(LoadIndex(index));
    }

    ReturnErrorOnFailure(SaveState(node, resumptionId, sharedSecret, peerCATs));
    ReturnErrorOnFailure(SaveLink(resumptionId, node));

    index.mNodes[index.mSize++] = node;
    ReturnErrorOnFailure(SaveIndex(index));

    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::Delete(const ScopedNodeId & node)
{
    SessionIndex index;
    ReturnErrorOnFailure(LoadIndex(index));

    ResumptionIdStorage resumptionId;
    Crypto::P256ECDHDerivedSecret sharedSecret;
    CATValues peerCATs;
    CHIP_ERROR err = LoadState(node, resumptionId, sharedSecret, peerCATs);
    if (err == CHIP_NO_ERROR)
    {
        err = DeleteLink(resumptionId);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Unable to delete session resumption link for node " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
                         ChipLogValueX64(node.GetNodeId()), err.Format());
        }
    }
    else if (err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
    {
        ChipLogError(SecureChannel,
                     "Unable to load session resumption state during session deletion for node " ChipLogFormatX64
                     ": %" CHIP_ERROR_FORMAT,
                     ChipLogValueX64(node.GetNodeId()), err.Format());
    }

    err = DeleteState(node);
    if (err != CHIP_NO_ERROR && err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
    {
        ChipLogError(SecureChannel, "Unable to delete session resumption state for node " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
                     ChipLogValueX64(node.GetNodeId()), err.Format());
    }

    bool found = false;
    for (size_t i = 0; i < index.mSize; ++i)
    {
        if (found)
        {
            // index.mSize was decreased by 1 when found was set to true.
            // So the (i+1)th element isn't out of bounds.
            index.mNodes[i] = index.mNodes[i + 1];
        }
        else
        {
            if (index.mNodes[i] == node)
            {
                found = true;
                if (i + 1 < index.mSize)
                {
                    index.mNodes[i] = index.mNodes[i + 1];
                }
                index.mSize -= 1;
            }
        }
    }

    if (found)
    {
        err = SaveIndex(index);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel, "Unable to save session resumption index: %" CHIP_ERROR_FORMAT, err.Format());
        }
    }
    else
    {
        ChipLogError(SecureChannel,
                     "Unable to find session resumption state for node in index" ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
                     ChipLogValueX64(node.GetNodeId()), err.Format());
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR DefaultSessionResumptionStorage::DeleteAll(FabricIndex fabricIndex)
{
    CHIP_ERROR stickyErr = CHIP_NO_ERROR;
    size_t found         = 0;
    SessionIndex index;
    ReturnErrorOnFailure(LoadIndex(index));
    size_t initialSize = index.mSize;
    for (size_t i = 0; i < initialSize; ++i)
    {
        CHIP_ERROR err = CHIP_NO_ERROR;
        size_t cur     = i - found;
        size_t remain  = initialSize - i;
        ResumptionIdStorage resumptionId;
        Crypto::P256ECDHDerivedSecret sharedSecret;
        CATValues peerCATs;
        if (index.mNodes[cur].GetFabricIndex() != fabricIndex)
        {
            continue;
        }
        err       = LoadState(index.mNodes[cur], resumptionId, sharedSecret, peerCATs);
        stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Session resumption cache deletion partially failed for fabric index %u, "
                         "unable to load node state: %" CHIP_ERROR_FORMAT,
                         fabricIndex, err.Format());
            continue;
        }
        err       = DeleteLink(resumptionId);
        stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Session resumption cache deletion partially failed for fabric index %u, "
                         "unable to delete node link: %" CHIP_ERROR_FORMAT,
                         fabricIndex, err.Format());
            continue;
        }
        err       = DeleteState(index.mNodes[cur]);
        stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(SecureChannel,
                         "Session resumption cache is in an inconsistent state!  "
                         "Unable to delete node state during attempted deletion of fabric index %u: %" CHIP_ERROR_FORMAT,
                         fabricIndex, err.Format());
            continue;
        }
        ++found;
        --remain;
        if (remain)
        {
            memmove(&index.mNodes[cur], &index.mNodes[cur + 1], remain * sizeof(index.mNodes[0]));
        }
    }
    if (found)
    {
        index.mSize -= found;
        CHIP_ERROR err = SaveIndex(index);
        stickyErr      = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(
                SecureChannel,
                "Session resumption cache is in an inconsistent state!  "
                "Unable to save session resumption index during atetmpted deletion of fabric index %u: %" CHIP_ERROR_FORMAT,
                fabricIndex, err.Format());
        }
    }
    return stickyErr;
}

} // namespace chip
<|endoftext|>


<commit_before>#include <v8.h>
#include "macros.h"
#include "gc.h"

#ifdef windows
#	include <my_global.h>
#endif

#include <mysql.h>
#include <stdlib.h>
#include <string>
#include <map>

#define MYSQL_ERROR mysql_error(conn)
#define ASSERT_CONNECTED if (!conn) { return JS_ERROR("No connection established yet."); }
#define ASSERT_RESULT if (!res) { return JS_ERROR("Result set already closed."); }
#define MYSQL_PTR MYSQL * conn = LOAD_PTR(0, MYSQL *)

namespace {

v8::Persistent<v8::FunctionTemplate> rest;
v8::Persistent<v8::FunctionTemplate> mysqlt;

typedef std::map<std::string, void *> persistent_connection_t;
persistent_connection_t persistent_connections;

void finalize(v8::Handle<v8::Object> obj) {
	v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(obj->Get(JS_STR("close")));
	fun->Call(obj, 0, NULL);
}

void result_finalize(v8::Handle<v8::Object> obj) {
	v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(obj->Get(JS_STR("close")));
	fun->Call(obj, 0, NULL);
}

v8::Handle<v8::Value> createResult(MYSQL * conn) {
	MYSQL_RES * res = mysql_store_result(conn);

	if (res) {
		v8::Handle<v8::Value> resargs[] = { v8::External::New((void *) res) };
		return rest->GetFunction()->NewInstance(1, resargs);
	} else {
		if (mysql_field_count(conn)) {
			return JS_ERROR(MYSQL_ERROR);
		} else {
			return JS_BOOL(true);
		}
	}
}

/**
 * MySQL constructor does basically nothing. It just adds "this.close()" method to global GC
 */
JS_METHOD(_mysql) {
	ASSERT_CONSTRUCTOR;
	SAVE_PTR(0, NULL);
	GC * gc = GC_PTR;
	gc->add(args.This(), finalize);
	return args.This();
}

/**
 * Close DB connection
 */
JS_METHOD(_close) {
	MYSQL_PTR;
	if (conn) {
		mysql_close(conn);
		SAVE_PTR(0, NULL);
	}
	return args.This();
}

/**
 * Should be called ASAP: new MySQL().connect("host", "user", "pass", "db")
 */
JS_METHOD(_connect) {
	if (args.Length() < 4) {
		return JS_TYPE_ERROR("Invalid call format. Use 'mysql.connect(host, user, pass, db)'");
	}

	MYSQL * conn;

	v8::String::Utf8Value host(args[0]);
	v8::String::Utf8Value user(args[1]);
	v8::String::Utf8Value pass(args[2]);
	v8::String::Utf8Value db(args[3]);

	std::string fullhost(*host);
	std::string onlyhost;
	int port = 0;

	size_t index = fullhost.find(':');
	if (index != std::string::npos) {
		onlyhost = fullhost.substr(0, index);
		port = atoi(fullhost.substr(index+1, fullhost.length()-index-1).c_str());
	} else {
		onlyhost = fullhost;
	}

	conn = mysql_init(NULL);
	if (!mysql_real_connect(conn, onlyhost.c_str(), *user, *pass, *db, port, NULL, CLIENT_MULTI_STATEMENTS)) {
		return JS_ERROR(MYSQL_ERROR);
	} else {
		mysql_query(conn, "SET NAMES 'utf8'");
		SAVE_PTR(0, conn);
		return args.This();
	}
}

/**
 * Query takes a string argument and returns an instance of Result object
 */
JS_METHOD(_query) {
	MYSQL_PTR;
	ASSERT_CONNECTED;
	if (args.Length() < 1) {
		return JS_ERROR("No query specified");
	}
	v8::String::Utf8Value q(args[0]);

	int code = mysql_real_query(conn, *q, q.length());
	if (code != 0) { return JS_ERROR(MYSQL_ERROR); }

	int qc = args.This()->Get(JS_STR("queryCount"))->ToInteger()->Int32Value();
	args.This()->Set(JS_STR("queryCount"), JS_INT(qc+1));

	return createResult(conn);
}

/**
 * Fetch next result from a multi-result set
 */
JS_METHOD(_nextresult) {
	MYSQL_PTR;
	ASSERT_CONNECTED;

	int status = mysql_next_result(conn);

	if (status == -1) { return JS_NULL; }
	if (status > 0) { return JS_ERROR(MYSQL_ERROR); }
	return createResult(conn);
}

JS_METHOD(_affectedrows) {
	MYSQL_PTR;
	ASSERT_CONNECTED;
	return JS_INT(mysql_affected_rows(conn));
}

JS_METHOD(_insertid) {
	MYSQL_PTR;
	ASSERT_CONNECTED;
	return JS_INT(mysql_insert_id(conn));
}

JS_METHOD(_escape) {
	MYSQL_PTR;
	ASSERT_CONNECTED;

	if (args.Length() < 1) {
		return JS_TYPE_ERROR("Nothing to escape");
	}
	v8::String::Utf8Value str(args[0]);

	int len = args[0]->ToString()->Utf8Length();
	char * result = new char[2*len + 1];

	int length = mysql_real_escape_string(conn, result, *str, len);
	v8::Handle<v8::Value> output = JS_STR(result, length);
	delete[] result;
	return output;
}

JS_METHOD(_qualify) {
	if (args.Length() < 1) {
		return JS_TYPE_ERROR("Nothing to qualify");
	}

	v8::String::Utf8Value str(args[0]);
	std::string result = "`";
	result += *str;
	result += "`";

	v8::Handle<v8::Value> output = JS_STR(result.c_str());
	return output;
}

JS_METHOD(_result) {
	SAVE_VALUE(0, args[0]);

	GC * gc = GC_PTR;
	gc->add(args.This(), result_finalize);

	return args.This();
}

JS_METHOD(_numrows) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;

	return JS_INT(mysql_num_rows(res));
}

JS_METHOD(_numfields) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;

	return JS_INT(mysql_num_fields(res));
}

JS_METHOD(_fetchnames) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;

	int cnt = mysql_num_fields(res);
	MYSQL_FIELD * fields = mysql_fetch_fields(res);
	v8::Handle<v8::Array> result = v8::Array::New(cnt);

	for(int i = 0; i < cnt; i++) {
		result->Set(JS_INT(i), JS_STR(fields[i].name));
	}

	return result;
}

/**
 * Converts string representations of values in MySQL result sets (the format in
 * which MySQL returns data) to JavaScript values.
 *
 * @param mysql_value  A string (or NULL) value fetched from MySQL.
 * @param field        The column the value came from.  Its type is used to
 *                     determine, e.g., whether to convert the value to a
 *                     number.
 */
v8::Handle<v8::Value> _mysqltojs(const char* mysql_value, const MYSQL_FIELD& field) {
	if (mysql_value == NULL) {
		return v8::Null();
	}

        // For type list, see http://www.google.com/codesearch/p#RGCD84x9Jg0/trunk/xbmc/lib/libcmyth/Win32/include/mysql/mysql_com.h&q=enum_field_types
	switch (field.type) {
		case MYSQL_TYPE_DECIMAL:
		case MYSQL_TYPE_TINY:
		case MYSQL_TYPE_SHORT:
		case MYSQL_TYPE_LONG:
		case MYSQL_TYPE_LONGLONG:
		case MYSQL_TYPE_INT24:
		case MYSQL_TYPE_BIT:
		case MYSQL_TYPE_NEWDECIMAL:
		case MYSQL_TYPE_ENUM:
		case MYSQL_TYPE_FLOAT:
		case MYSQL_TYPE_DOUBLE:
			return JS_STR(mysql_value)->ToNumber();

		case MYSQL_TYPE_TIMESTAMP:
		case MYSQL_TYPE_DATE:
		case MYSQL_TYPE_TIME:
		case MYSQL_TYPE_DATETIME:
		case MYSQL_TYPE_YEAR:
		case MYSQL_TYPE_NEWDATE:
			return JS_STR(mysql_value);  // TODO: handle dates appropriately

		default:
			return JS_STR(mysql_value);
        }
}

/**
 * Return result data as an array of JS arrays
 */
JS_METHOD(_fetcharrays) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;
	mysql_data_seek(res, 0);

	int x = mysql_num_fields(res);
	int y = mysql_num_rows(res);
	MYSQL_FIELD * fields = mysql_fetch_fields(res);
	MYSQL_ROW row;
	v8::Handle<v8::Array> result = v8::Array::New(y);

	for (int i = 0; i < y; i++) {
		row = mysql_fetch_row(res);
		v8::Handle<v8::Array> item = v8::Array::New(x);
		result->Set(JS_INT(i), item);
		for (int j=0; j<x; j++) {
			item->Set(JS_INT(j), _mysqltojs(row[j], fields[j]));
			}
		}

	return result;
}

/**
 * Return result data as an array of JS objects, indexed with column names
 */
JS_METHOD(_fetchobjects) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;
	mysql_data_seek(res, 0);

	int x = mysql_num_fields(res);
	int y = mysql_num_rows(res);
	MYSQL_FIELD * fields = mysql_fetch_fields(res);
	MYSQL_ROW row;
	v8::Handle<v8::Array> result = v8::Array::New(y);

	for (int i = 0; i < y; i++) {
		row = mysql_fetch_row(res);
		v8::Handle<v8::Object> item = v8::Object::New();
		result->Set(JS_INT(i), item);
		for (int j=0; j<x; j++) {
			item->Set(JS_STR(fields[j].name), _mysqltojs(row[j], fields[j]));
			}
		}

	return result;
}

JS_METHOD(_result_close) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	if (res) {
		mysql_free_result(res);
		SAVE_PTR(0, NULL);
		return JS_BOOL(true);
	} else {
		return JS_BOOL(false);
	}
}

JS_METHOD(_storeConnection) {
	v8::String::Utf8Value name(args[0]);
	std::string str_name(*name);

	persistent_connection_t::iterator it = persistent_connections.find(str_name);
	if (args[1]->IsFalse()) { /* delete */
		persistent_connections.erase(it);
		return JS_UNDEFINED;
	}

	if (!args[1]->IsObject()) { return JS_TYPE_ERROR("Invalid argument"); }
	v8::Handle<v8::Object> inst = v8::Handle<v8::Object>::Cast(args[1]);
	if (inst->InternalFieldCount() < 1) { return JS_TYPE_ERROR("Invalid argument"); }

	if (it != persistent_connections.end()) { return JS_ERROR("Connection name already used"); }

	persistent_connections[str_name] = inst->GetPointerFromInternalField(0);
	return JS_UNDEFINED;

}

JS_METHOD(_loadConnection) {
	v8::String::Utf8Value name(args[0]);
	std::string str_name(*name);

	persistent_connection_t::iterator it = persistent_connections.find(str_name);
	if (it == persistent_connections.end()) { return JS_NULL; }

	MYSQL * conn = (MYSQL *) (it->second);
	v8::Handle<v8::Object> inst = mysqlt->GetFunction()->NewInstance();
	inst->SetPointerInInternalField(0, (void *)conn);

	return inst;
}

} /* end namespace */

SHARED_INIT() {
	v8::HandleScope handle_scope;
	mysqlt = v8::Persistent<v8::FunctionTemplate>::New(_mysql);
	mysqlt->SetClassName(JS_STR("MySQL"));

	v8::Handle<v8::ObjectTemplate> ot = mysqlt->InstanceTemplate();
	ot->SetInternalFieldCount(1); /* connection */

	/**
	 * Static property, useful for stats gathering
	 */
	ot->Set(JS_STR("queryCount"), JS_INT(0));

	/**
	 * Persistent connection storage
	 */
	mysqlt->Set(JS_STR("storeConnection"), v8::FunctionTemplate::New(_storeConnection));
	mysqlt->Set(JS_STR("loadConnection"), v8::FunctionTemplate::New(_loadConnection));

	v8::Handle<v8::ObjectTemplate> pt = mysqlt->PrototypeTemplate();

	/**
	 * MySQL prototype methods (new MySQL().*)
	 */
	pt->Set(JS_STR("connect"), v8::FunctionTemplate::New(_connect));
	pt->Set(JS_STR("close"), v8::FunctionTemplate::New(_close));
	pt->Set(JS_STR("query"), v8::FunctionTemplate::New(_query));
	pt->Set(JS_STR("nextResult"), v8::FunctionTemplate::New(_nextresult));
	pt->Set(JS_STR("affectedRows"), v8::FunctionTemplate::New(_affectedrows));
	pt->Set(JS_STR("escape"), v8::FunctionTemplate::New(_escape));
	pt->Set(JS_STR("qualify"), v8::FunctionTemplate::New(_qualify));
	pt->Set(JS_STR("insertId"), v8::FunctionTemplate::New(_insertid));

	rest = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(_result));
	rest->SetClassName(JS_STR("Result"));

	v8::Handle<v8::ObjectTemplate> resinst = rest->InstanceTemplate();
	resinst->SetInternalFieldCount(1);

	v8::Handle<v8::ObjectTemplate> resproto = rest->PrototypeTemplate();

	/**
	 * Result prototype methods (new MySQL().query().*)
	 */
	resproto->Set(JS_STR("numRows"), v8::FunctionTemplate::New(_numrows));
	resproto->Set(JS_STR("numFields"), v8::FunctionTemplate::New(_numfields));
	resproto->Set(JS_STR("fetchNames"), v8::FunctionTemplate::New(_fetchnames));
	resproto->Set(JS_STR("fetchArrays"), v8::FunctionTemplate::New(_fetcharrays));
	resproto->Set(JS_STR("fetchObjects"), v8::FunctionTemplate::New(_fetchobjects));
	resproto->Set(JS_STR("close"), v8::FunctionTemplate::New(_result_close));

	exports->Set(JS_STR("MySQL"), mysqlt->GetFunction());
}
<commit_msg>persistent template fix<commit_after>#include <v8.h>
#include "macros.h"
#include "gc.h"

#ifdef windows
#	include <my_global.h>
#endif

#include <mysql.h>
#include <stdlib.h>
#include <string>
#include <map>

#define MYSQL_ERROR mysql_error(conn)
#define ASSERT_CONNECTED if (!conn) { return JS_ERROR("No connection established yet."); }
#define ASSERT_RESULT if (!res) { return JS_ERROR("Result set already closed."); }
#define MYSQL_PTR MYSQL * conn = LOAD_PTR(0, MYSQL *)

namespace {

v8::Persistent<v8::FunctionTemplate> rest;
v8::Persistent<v8::FunctionTemplate> mysqlt;

typedef std::map<std::string, void *> persistent_connection_t;
persistent_connection_t persistent_connections;

void finalize(v8::Handle<v8::Object> obj) {
	v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(obj->Get(JS_STR("close")));
	fun->Call(obj, 0, NULL);
}

void result_finalize(v8::Handle<v8::Object> obj) {
	v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(obj->Get(JS_STR("close")));
	fun->Call(obj, 0, NULL);
}

v8::Handle<v8::Value> createResult(MYSQL * conn) {
	MYSQL_RES * res = mysql_store_result(conn);

	if (res) {
		v8::Handle<v8::Value> resargs[] = { v8::External::New((void *) res) };
		return rest->GetFunction()->NewInstance(1, resargs);
	} else {
		if (mysql_field_count(conn)) {
			return JS_ERROR(MYSQL_ERROR);
		} else {
			return JS_BOOL(true);
		}
	}
}

/**
 * MySQL constructor does basically nothing. It just adds "this.close()" method to global GC
 */
JS_METHOD(_mysql) {
	ASSERT_CONSTRUCTOR;
	SAVE_PTR(0, NULL);
	GC * gc = GC_PTR;
	gc->add(args.This(), finalize);
	return args.This();
}

/**
 * Close DB connection
 */
JS_METHOD(_close) {
	MYSQL_PTR;
	if (conn) {
		mysql_close(conn);
		SAVE_PTR(0, NULL);
	}
	return args.This();
}

/**
 * Should be called ASAP: new MySQL().connect("host", "user", "pass", "db")
 */
JS_METHOD(_connect) {
	if (args.Length() < 4) {
		return JS_TYPE_ERROR("Invalid call format. Use 'mysql.connect(host, user, pass, db)'");
	}

	MYSQL * conn;

	v8::String::Utf8Value host(args[0]);
	v8::String::Utf8Value user(args[1]);
	v8::String::Utf8Value pass(args[2]);
	v8::String::Utf8Value db(args[3]);

	std::string fullhost(*host);
	std::string onlyhost;
	int port = 0;

	size_t index = fullhost.find(':');
	if (index != std::string::npos) {
		onlyhost = fullhost.substr(0, index);
		port = atoi(fullhost.substr(index+1, fullhost.length()-index-1).c_str());
	} else {
		onlyhost = fullhost;
	}

	conn = mysql_init(NULL);
	if (!mysql_real_connect(conn, onlyhost.c_str(), *user, *pass, *db, port, NULL, CLIENT_MULTI_STATEMENTS)) {
		return JS_ERROR(MYSQL_ERROR);
	} else {
		mysql_query(conn, "SET NAMES 'utf8'");
		SAVE_PTR(0, conn);
		return args.This();
	}
}

/**
 * Query takes a string argument and returns an instance of Result object
 */
JS_METHOD(_query) {
	MYSQL_PTR;
	ASSERT_CONNECTED;
	if (args.Length() < 1) {
		return JS_ERROR("No query specified");
	}
	v8::String::Utf8Value q(args[0]);

	int code = mysql_real_query(conn, *q, q.length());
	if (code != 0) { return JS_ERROR(MYSQL_ERROR); }

	int qc = args.This()->Get(JS_STR("queryCount"))->ToInteger()->Int32Value();
	args.This()->Set(JS_STR("queryCount"), JS_INT(qc+1));

	return createResult(conn);
}

/**
 * Fetch next result from a multi-result set
 */
JS_METHOD(_nextresult) {
	MYSQL_PTR;
	ASSERT_CONNECTED;

	int status = mysql_next_result(conn);

	if (status == -1) { return JS_NULL; }
	if (status > 0) { return JS_ERROR(MYSQL_ERROR); }
	return createResult(conn);
}

JS_METHOD(_affectedrows) {
	MYSQL_PTR;
	ASSERT_CONNECTED;
	return JS_INT(mysql_affected_rows(conn));
}

JS_METHOD(_insertid) {
	MYSQL_PTR;
	ASSERT_CONNECTED;
	return JS_INT(mysql_insert_id(conn));
}

JS_METHOD(_escape) {
	MYSQL_PTR;
	ASSERT_CONNECTED;

	if (args.Length() < 1) {
		return JS_TYPE_ERROR("Nothing to escape");
	}
	v8::String::Utf8Value str(args[0]);

	int len = args[0]->ToString()->Utf8Length();
	char * result = new char[2*len + 1];

	int length = mysql_real_escape_string(conn, result, *str, len);
	v8::Handle<v8::Value> output = JS_STR(result, length);
	delete[] result;
	return output;
}

JS_METHOD(_qualify) {
	if (args.Length() < 1) {
		return JS_TYPE_ERROR("Nothing to qualify");
	}

	v8::String::Utf8Value str(args[0]);
	std::string result = "`";
	result += *str;
	result += "`";

	v8::Handle<v8::Value> output = JS_STR(result.c_str());
	return output;
}

JS_METHOD(_result) {
	SAVE_VALUE(0, args[0]);

	GC * gc = GC_PTR;
	gc->add(args.This(), result_finalize);

	return args.This();
}

JS_METHOD(_numrows) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;

	return JS_INT(mysql_num_rows(res));
}

JS_METHOD(_numfields) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;

	return JS_INT(mysql_num_fields(res));
}

JS_METHOD(_fetchnames) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;

	int cnt = mysql_num_fields(res);
	MYSQL_FIELD * fields = mysql_fetch_fields(res);
	v8::Handle<v8::Array> result = v8::Array::New(cnt);

	for(int i = 0; i < cnt; i++) {
		result->Set(JS_INT(i), JS_STR(fields[i].name));
	}

	return result;
}

/**
 * Converts string representations of values in MySQL result sets (the format in
 * which MySQL returns data) to JavaScript values.
 *
 * @param mysql_value  A string (or NULL) value fetched from MySQL.
 * @param field        The column the value came from.  Its type is used to
 *                     determine, e.g., whether to convert the value to a
 *                     number.
 */
v8::Handle<v8::Value> _mysqltojs(const char* mysql_value, const MYSQL_FIELD& field) {
	if (mysql_value == NULL) {
		return v8::Null();
	}

        // For type list, see http://www.google.com/codesearch/p#RGCD84x9Jg0/trunk/xbmc/lib/libcmyth/Win32/include/mysql/mysql_com.h&q=enum_field_types
	switch (field.type) {
		case MYSQL_TYPE_DECIMAL:
		case MYSQL_TYPE_TINY:
		case MYSQL_TYPE_SHORT:
		case MYSQL_TYPE_LONG:
		case MYSQL_TYPE_LONGLONG:
		case MYSQL_TYPE_INT24:
		case MYSQL_TYPE_BIT:
		case MYSQL_TYPE_NEWDECIMAL:
		case MYSQL_TYPE_ENUM:
		case MYSQL_TYPE_FLOAT:
		case MYSQL_TYPE_DOUBLE:
			return JS_STR(mysql_value)->ToNumber();

		case MYSQL_TYPE_TIMESTAMP:
		case MYSQL_TYPE_DATE:
		case MYSQL_TYPE_TIME:
		case MYSQL_TYPE_DATETIME:
		case MYSQL_TYPE_YEAR:
		case MYSQL_TYPE_NEWDATE:
			return JS_STR(mysql_value);  // TODO: handle dates appropriately

		default:
			return JS_STR(mysql_value);
        }
}

/**
 * Return result data as an array of JS arrays
 */
JS_METHOD(_fetcharrays) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;
	mysql_data_seek(res, 0);

	int x = mysql_num_fields(res);
	int y = mysql_num_rows(res);
	MYSQL_FIELD * fields = mysql_fetch_fields(res);
	MYSQL_ROW row;
	v8::Handle<v8::Array> result = v8::Array::New(y);

	for (int i = 0; i < y; i++) {
		row = mysql_fetch_row(res);
		v8::Handle<v8::Array> item = v8::Array::New(x);
		result->Set(JS_INT(i), item);
		for (int j=0; j<x; j++) {
			item->Set(JS_INT(j), _mysqltojs(row[j], fields[j]));
			}
		}

	return result;
}

/**
 * Return result data as an array of JS objects, indexed with column names
 */
JS_METHOD(_fetchobjects) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	ASSERT_RESULT;
	mysql_data_seek(res, 0);

	int x = mysql_num_fields(res);
	int y = mysql_num_rows(res);
	MYSQL_FIELD * fields = mysql_fetch_fields(res);
	MYSQL_ROW row;
	v8::Handle<v8::Array> result = v8::Array::New(y);

	for (int i = 0; i < y; i++) {
		row = mysql_fetch_row(res);
		v8::Handle<v8::Object> item = v8::Object::New();
		result->Set(JS_INT(i), item);
		for (int j=0; j<x; j++) {
			item->Set(JS_STR(fields[j].name), _mysqltojs(row[j], fields[j]));
			}
		}

	return result;
}

JS_METHOD(_result_close) {
	MYSQL_RES * res = LOAD_PTR(0, MYSQL_RES *);
	if (res) {
		mysql_free_result(res);
		SAVE_PTR(0, NULL);
		return JS_BOOL(true);
	} else {
		return JS_BOOL(false);
	}
}

JS_METHOD(_storeConnection) {
	v8::String::Utf8Value name(args[0]);
	std::string str_name(*name);

	persistent_connection_t::iterator it = persistent_connections.find(str_name);
	if (args[1]->IsFalse()) { /* delete */
		persistent_connections.erase(it);
		return JS_UNDEFINED;
	}

	if (!args[1]->IsObject()) { return JS_TYPE_ERROR("Invalid argument"); }
	v8::Handle<v8::Object> inst = v8::Handle<v8::Object>::Cast(args[1]);
	if (inst->InternalFieldCount() < 1) { return JS_TYPE_ERROR("Invalid argument"); }

	if (it != persistent_connections.end()) { return JS_ERROR("Connection name already used"); }

	persistent_connections[str_name] = inst->GetPointerFromInternalField(0);
	return JS_UNDEFINED;

}

JS_METHOD(_loadConnection) {
	v8::String::Utf8Value name(args[0]);
	std::string str_name(*name);

	persistent_connection_t::iterator it = persistent_connections.find(str_name);
	if (it == persistent_connections.end()) { return JS_NULL; }

	MYSQL * conn = (MYSQL *) (it->second);
	v8::Handle<v8::Object> inst = mysqlt->GetFunction()->NewInstance();
	inst->SetPointerInInternalField(0, (void *)conn);

	return inst;
}

} /* end namespace */

SHARED_INIT() {
	v8::HandleScope handle_scope;
	mysqlt = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(_mysql));
	mysqlt->SetClassName(JS_STR("MySQL"));

	v8::Handle<v8::ObjectTemplate> ot = mysqlt->InstanceTemplate();
	ot->SetInternalFieldCount(1); /* connection */

	/**
	 * Static property, useful for stats gathering
	 */
	ot->Set(JS_STR("queryCount"), JS_INT(0));

	/**
	 * Persistent connection storage
	 */
	mysqlt->Set(JS_STR("storeConnection"), v8::FunctionTemplate::New(_storeConnection));
	mysqlt->Set(JS_STR("loadConnection"), v8::FunctionTemplate::New(_loadConnection));

	v8::Handle<v8::ObjectTemplate> pt = mysqlt->PrototypeTemplate();

	/**
	 * MySQL prototype methods (new MySQL().*)
	 */
	pt->Set(JS_STR("connect"), v8::FunctionTemplate::New(_connect));
	pt->Set(JS_STR("close"), v8::FunctionTemplate::New(_close));
	pt->Set(JS_STR("query"), v8::FunctionTemplate::New(_query));
	pt->Set(JS_STR("nextResult"), v8::FunctionTemplate::New(_nextresult));
	pt->Set(JS_STR("affectedRows"), v8::FunctionTemplate::New(_affectedrows));
	pt->Set(JS_STR("escape"), v8::FunctionTemplate::New(_escape));
	pt->Set(JS_STR("qualify"), v8::FunctionTemplate::New(_qualify));
	pt->Set(JS_STR("insertId"), v8::FunctionTemplate::New(_insertid));

	rest = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(_result));
	rest->SetClassName(JS_STR("Result"));

	v8::Handle<v8::ObjectTemplate> resinst = rest->InstanceTemplate();
	resinst->SetInternalFieldCount(1);

	v8::Handle<v8::ObjectTemplate> resproto = rest->PrototypeTemplate();

	/**
	 * Result prototype methods (new MySQL().query().*)
	 */
	resproto->Set(JS_STR("numRows"), v8::FunctionTemplate::New(_numrows));
	resproto->Set(JS_STR("numFields"), v8::FunctionTemplate::New(_numfields));
	resproto->Set(JS_STR("fetchNames"), v8::FunctionTemplate::New(_fetchnames));
	resproto->Set(JS_STR("fetchArrays"), v8::FunctionTemplate::New(_fetcharrays));
	resproto->Set(JS_STR("fetchObjects"), v8::FunctionTemplate::New(_fetchobjects));
	resproto->Set(JS_STR("close"), v8::FunctionTemplate::New(_result_close));

	exports->Set(JS_STR("MySQL"), mysqlt->GetFunction());
}
<|endoftext|>


<commit_before><commit_msg>class metho<commit_after><|endoftext|>


<commit_before>#include "chrono_parallel/lcp/ChLcpSolverParallel.h"
#include "chrono_parallel/math/ChThrustLinearAlgebra.h"

#include "chrono_parallel/solver/ChSolverAPGD.h"
#include "chrono_parallel/solver/ChSolverAPGDREF.h"
#include "chrono_parallel/solver/ChSolverBiCG.h"
#include "chrono_parallel/solver/ChSolverBiCGStab.h"
#include "chrono_parallel/solver/ChSolverCG.h"
#include "chrono_parallel/solver/ChSolverCGS.h"
#include "chrono_parallel/solver/ChSolverMinRes.h"
#include "chrono_parallel/solver/ChSolverSD.h"
#include "chrono_parallel/solver/ChSolverGD.h"
#include "chrono_parallel/solver/ChSolverPGS.h"
#include "chrono_parallel/solver/ChSolverJacobi.h"
#include "chrono_parallel/solver/ChSolverPDIP.h"
using namespace chrono;

void ChLcpSolverParallelDVI::RunTimeStep(real step) {
  // Setup constants and other values for system

  data_container->settings.step_size = step;

  // Compute the offsets and number of constrains depending on the solver
  // mode
  if (data_container->settings.solver.solver_mode == NORMAL) {
    rigid_rigid.offset = 1;
    data_container->num_unilaterals = 1 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SLIDING) {
    rigid_rigid.offset = 3;
    data_container->num_unilaterals = 3 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SPINNING) {
    rigid_rigid.offset = 6;
    data_container->num_unilaterals = 6 * data_container->num_contacts;
  }
  // This is the total number of constraints
  data_container->num_constraints = data_container->num_unilaterals + data_container->num_bilaterals;
  // This is the total number of degrees of freedom in the system
  data_container->num_dof = data_container->num_bodies * 6 + data_container->num_shafts;

  // Generate the mass matrix and compute M_inv_k
  ComputeMassMatrix();

  data_container->host_data.gamma.resize(data_container->num_constraints);
  data_container->host_data.gamma.reset();

  // Perform any setup tasks for all constraint types
  rigid_rigid.Setup(data_container);
  bilateral.Setup(data_container);
  // Clear and reset solver history data and counters
  solver->current_iteration = 0;
  data_container->measures.solver.total_iteration = 0;
  data_container->measures.solver.maxd_hist.clear();
  data_container->measures.solver.maxdeltalambda_hist.clear();
  data_container->measures.solver.iter_hist.clear();
  // Set pointers to constraint objects and perform setup actions for solver
  solver->rigid_rigid = &rigid_rigid;
  solver->bilateral = &bilateral;
  solver->Setup(data_container);

  ComputeD();
  ComputeE();

  // Copy gamma values for bilaterals from the previous timestep
  // these will be used to warm start the bilateral solution
#pragma omp parallel for
  for (int i = 0; i < data_container->num_bilaterals; i++) {
    data_container->host_data.gamma[i + data_container->num_unilaterals] = data_container->host_data.gamma_bilateral[i];
  }

  // solve for the normal
  if (data_container->settings.solver.solver_mode == NORMAL || data_container->settings.solver.solver_mode == SLIDING || data_container->settings.solver.solver_mode == SPINNING) {
    if (data_container->settings.solver.max_iteration_normal > 0) {
      solver->SetMaxIterations(data_container->settings.solver.max_iteration_normal);
      rigid_rigid.solve_sliding = false;
      rigid_rigid.solve_spinning = false;
      ComputeR(NORMAL);
      data_container->system_timer.start("ChLcpSolverParallel_Solve");
      PerformStabilization();
      solver->Solve();
      data_container->system_timer.stop("ChLcpSolverParallel_Solve");
    }
  }
  if (data_container->settings.solver.solver_mode != NORMAL) {
    if (data_container->settings.solver.max_iteration_sliding > 0) {
      solver->SetMaxIterations(data_container->settings.solver.max_iteration_sliding);
      rigid_rigid.solve_sliding = true;
      rigid_rigid.solve_spinning = false;
      ComputeR(SLIDING);
      data_container->system_timer.start("ChLcpSolverParallel_Solve");
      PerformStabilization();
      solver->Solve();
      data_container->system_timer.stop("ChLcpSolverParallel_Solve");
    }
  }
  if (data_container->settings.solver.solver_mode == SPINNING) {
    if (data_container->settings.solver.max_iteration_spinning > 0) {
      solver->SetMaxIterations(data_container->settings.solver.max_iteration_spinning);
      rigid_rigid.solve_sliding = true;
      rigid_rigid.solve_spinning = true;
      ComputeR(SPINNING);
      data_container->system_timer.start("ChLcpSolverParallel_Solve");
      PerformStabilization();
      solver->Solve();
      data_container->system_timer.stop("ChLcpSolverParallel_Solve");
    }
  }

  data_container->host_data.gamma_bilateral.resize(data_container->num_bilaterals);

#pragma omp parallel for
  for (int i = 0; i < data_container->num_bilaterals; i++) {
    data_container->host_data.gamma_bilateral[i] = data_container->host_data.gamma[i + data_container->num_unilaterals];
  }

  ComputeImpulses();

  if (tot_iterations > 0) {
    for (int i = 0; i <  data_container->measures.solver.iter_hist.size(); i++) {
      AtIterationEnd( data_container->measures.solver.maxd_hist[i],  data_container->measures.solver.maxdeltalambda_hist[i],  data_container->measures.solver.iter_hist[i]);
    }
  }

#if PRINT_LEVEL == 2
  std::cout << "Solve Done: " << residual << std::endl;
#endif
}

void ChLcpSolverParallelDVI::ComputeD() {

  CompressedMatrix<real>& D_T = data_container->host_data.D_T;

  uint& num_constraints = data_container->num_constraints;
  uint& num_bodies = data_container->num_bodies;
  uint& num_shafts = data_container->num_shafts;
  uint& num_dof = data_container->num_dof;
  uint& num_contacts = data_container->num_contacts;
  uint& num_bilaterals = data_container->num_bilaterals;
  if (num_constraints <= 0) {
    return;
  }
  clear(D_T);

  int unilateral_reserve = 0;

  if (data_container->settings.solver.solver_mode == NORMAL) {
    unilateral_reserve = 6 * 2 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SLIDING) {
    unilateral_reserve = 6 * 6 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SPINNING) {
    unilateral_reserve = 6 * 9 * data_container->num_contacts;
  }

  int constraint_reserve = unilateral_reserve + num_bilaterals * 6 * 2;

  if (D_T.capacity() < constraint_reserve) {
    D_T.reserve(constraint_reserve * 1.2);
  }

  D_T.resize(num_constraints, num_dof, false);
  rigid_rigid.GenerateSparsity(data_container->settings.solver.solver_mode);
  bilateral.GenerateSparsity();
  rigid_rigid.Build_D(data_container->settings.solver.solver_mode);
  bilateral.Build_D();

  data_container->host_data.D = trans(data_container->host_data.D_T);
  data_container->host_data.M_invD = data_container->host_data.M_inv * data_container->host_data.D;
}

void ChLcpSolverParallelDVI::ComputeE() {

  uint& num_constraints = data_container->num_constraints;
  if (num_constraints <= 0) {
    return;
  }
  DynamicVector<real>& E = data_container->host_data.E;
  E.resize(num_constraints);
  reset(E);

  rigid_rigid.Build_E(data_container->settings.solver.solver_mode);
  bilateral.Build_E();
}

void ChLcpSolverParallelDVI::ComputeR(SOLVERMODE mode) {
  if (data_container->num_constraints <= 0) {
    return;
  }
  data_container->host_data.b.resize(data_container->num_constraints);
  reset(data_container->host_data.b);

  rigid_rigid.Build_b(mode);
  bilateral.Build_b();

  data_container->host_data.R = -data_container->host_data.b - data_container->host_data.D_T * data_container->host_data.M_invk;
}

void ChLcpSolverParallelDVI::ChangeSolverType(SOLVERTYPE type) {
  data_container->settings.solver.solver_type = type;

  if (this->solver) {
    delete (this->solver);
  }
  if (type == STEEPEST_DESCENT) {
    solver = new ChSolverSD();
  } else if (type == GRADIENT_DESCENT) {
    solver = new ChSolverGD();
  } else if (type == CONJUGATE_GRADIENT) {
    solver = new ChSolverCG();
  } else if (type == CONJUGATE_GRADIENT_SQUARED) {
    solver = new ChSolverCGS();
  } else if (type == BICONJUGATE_GRADIENT) {
    solver = new ChSolverBiCG();
  } else if (type == BICONJUGATE_GRADIENT_STAB) {
    solver = new ChSolverBiCGStab();
  } else if (type == MINIMUM_RESIDUAL) {
    solver = new ChSolverMinRes();
  } else if (type == QUASAI_MINIMUM_RESIDUAL) {
    //         // This solver has not been implemented yet
    //         //SolveQMR(data_container->gpu_data.device_gam_data, rhs, max_iteration);
  } else if (type == APGD) {
    solver = new ChSolverAPGD();
  } else if (type == APGDREF) {
    solver = new ChSolverAPGDREF();
  } else if (type == JACOBI) {
    solver = new ChSolverJacobi();
  } else if (type == GAUSS_SEIDEL) {
    solver = new ChSolverPGS();
  } else if (type == PDIP) {
    solver = new ChSolverPDIP();
  }
}
<commit_msg>tot_iteration is currently not set, the for loop would take care of the condition where there is no history anyways<commit_after>#include "chrono_parallel/lcp/ChLcpSolverParallel.h"
#include "chrono_parallel/math/ChThrustLinearAlgebra.h"

#include "chrono_parallel/solver/ChSolverAPGD.h"
#include "chrono_parallel/solver/ChSolverAPGDREF.h"
#include "chrono_parallel/solver/ChSolverBiCG.h"
#include "chrono_parallel/solver/ChSolverBiCGStab.h"
#include "chrono_parallel/solver/ChSolverCG.h"
#include "chrono_parallel/solver/ChSolverCGS.h"
#include "chrono_parallel/solver/ChSolverMinRes.h"
#include "chrono_parallel/solver/ChSolverSD.h"
#include "chrono_parallel/solver/ChSolverGD.h"
#include "chrono_parallel/solver/ChSolverPGS.h"
#include "chrono_parallel/solver/ChSolverJacobi.h"
#include "chrono_parallel/solver/ChSolverPDIP.h"
using namespace chrono;

void ChLcpSolverParallelDVI::RunTimeStep(real step) {
  // Setup constants and other values for system

  data_container->settings.step_size = step;

  // Compute the offsets and number of constrains depending on the solver
  // mode
  if (data_container->settings.solver.solver_mode == NORMAL) {
    rigid_rigid.offset = 1;
    data_container->num_unilaterals = 1 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SLIDING) {
    rigid_rigid.offset = 3;
    data_container->num_unilaterals = 3 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SPINNING) {
    rigid_rigid.offset = 6;
    data_container->num_unilaterals = 6 * data_container->num_contacts;
  }
  // This is the total number of constraints
  data_container->num_constraints = data_container->num_unilaterals + data_container->num_bilaterals;
  // This is the total number of degrees of freedom in the system
  data_container->num_dof = data_container->num_bodies * 6 + data_container->num_shafts;

  // Generate the mass matrix and compute M_inv_k
  ComputeMassMatrix();

  data_container->host_data.gamma.resize(data_container->num_constraints);
  data_container->host_data.gamma.reset();

  // Perform any setup tasks for all constraint types
  rigid_rigid.Setup(data_container);
  bilateral.Setup(data_container);
  // Clear and reset solver history data and counters
  solver->current_iteration = 0;
  data_container->measures.solver.total_iteration = 0;
  data_container->measures.solver.maxd_hist.clear();
  data_container->measures.solver.maxdeltalambda_hist.clear();
  data_container->measures.solver.iter_hist.clear();
  // Set pointers to constraint objects and perform setup actions for solver
  solver->rigid_rigid = &rigid_rigid;
  solver->bilateral = &bilateral;
  solver->Setup(data_container);

  ComputeD();
  ComputeE();

  // Copy gamma values for bilaterals from the previous timestep
  // these will be used to warm start the bilateral solution
#pragma omp parallel for
  for (int i = 0; i < data_container->num_bilaterals; i++) {
    data_container->host_data.gamma[i + data_container->num_unilaterals] = data_container->host_data.gamma_bilateral[i];
  }

  // solve for the normal
  if (data_container->settings.solver.solver_mode == NORMAL || data_container->settings.solver.solver_mode == SLIDING || data_container->settings.solver.solver_mode == SPINNING) {
    if (data_container->settings.solver.max_iteration_normal > 0) {
      solver->SetMaxIterations(data_container->settings.solver.max_iteration_normal);
      rigid_rigid.solve_sliding = false;
      rigid_rigid.solve_spinning = false;
      ComputeR(NORMAL);
      data_container->system_timer.start("ChLcpSolverParallel_Solve");
      PerformStabilization();
      solver->Solve();
      data_container->system_timer.stop("ChLcpSolverParallel_Solve");
    }
  }
  if (data_container->settings.solver.solver_mode != NORMAL) {
    if (data_container->settings.solver.max_iteration_sliding > 0) {
      solver->SetMaxIterations(data_container->settings.solver.max_iteration_sliding);
      rigid_rigid.solve_sliding = true;
      rigid_rigid.solve_spinning = false;
      ComputeR(SLIDING);
      data_container->system_timer.start("ChLcpSolverParallel_Solve");
      PerformStabilization();
      solver->Solve();
      data_container->system_timer.stop("ChLcpSolverParallel_Solve");
    }
  }
  if (data_container->settings.solver.solver_mode == SPINNING) {
    if (data_container->settings.solver.max_iteration_spinning > 0) {
      solver->SetMaxIterations(data_container->settings.solver.max_iteration_spinning);
      rigid_rigid.solve_sliding = true;
      rigid_rigid.solve_spinning = true;
      ComputeR(SPINNING);
      data_container->system_timer.start("ChLcpSolverParallel_Solve");
      PerformStabilization();
      solver->Solve();
      data_container->system_timer.stop("ChLcpSolverParallel_Solve");
    }
  }

  data_container->host_data.gamma_bilateral.resize(data_container->num_bilaterals);

#pragma omp parallel for
  for (int i = 0; i < data_container->num_bilaterals; i++) {
    data_container->host_data.gamma_bilateral[i] = data_container->host_data.gamma[i + data_container->num_unilaterals];
  }

  ComputeImpulses();

    for (int i = 0; i <  data_container->measures.solver.iter_hist.size(); i++) {
      AtIterationEnd( data_container->measures.solver.maxd_hist[i],  data_container->measures.solver.maxdeltalambda_hist[i],  data_container->measures.solver.iter_hist[i]);
  }

#if PRINT_LEVEL == 2
  std::cout << "Solve Done: " << residual << std::endl;
#endif
}

void ChLcpSolverParallelDVI::ComputeD() {

  CompressedMatrix<real>& D_T = data_container->host_data.D_T;

  uint& num_constraints = data_container->num_constraints;
  uint& num_bodies = data_container->num_bodies;
  uint& num_shafts = data_container->num_shafts;
  uint& num_dof = data_container->num_dof;
  uint& num_contacts = data_container->num_contacts;
  uint& num_bilaterals = data_container->num_bilaterals;
  if (num_constraints <= 0) {
    return;
  }
  clear(D_T);

  int unilateral_reserve = 0;

  if (data_container->settings.solver.solver_mode == NORMAL) {
    unilateral_reserve = 6 * 2 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SLIDING) {
    unilateral_reserve = 6 * 6 * data_container->num_contacts;
  } else if (data_container->settings.solver.solver_mode == SPINNING) {
    unilateral_reserve = 6 * 9 * data_container->num_contacts;
  }

  int constraint_reserve = unilateral_reserve + num_bilaterals * 6 * 2;

  if (D_T.capacity() < constraint_reserve) {
    D_T.reserve(constraint_reserve * 1.2);
  }

  D_T.resize(num_constraints, num_dof, false);
  rigid_rigid.GenerateSparsity(data_container->settings.solver.solver_mode);
  bilateral.GenerateSparsity();
  rigid_rigid.Build_D(data_container->settings.solver.solver_mode);
  bilateral.Build_D();

  data_container->host_data.D = trans(data_container->host_data.D_T);
  data_container->host_data.M_invD = data_container->host_data.M_inv * data_container->host_data.D;
}

void ChLcpSolverParallelDVI::ComputeE() {

  uint& num_constraints = data_container->num_constraints;
  if (num_constraints <= 0) {
    return;
  }
  DynamicVector<real>& E = data_container->host_data.E;
  E.resize(num_constraints);
  reset(E);

  rigid_rigid.Build_E(data_container->settings.solver.solver_mode);
  bilateral.Build_E();
}

void ChLcpSolverParallelDVI::ComputeR(SOLVERMODE mode) {
  if (data_container->num_constraints <= 0) {
    return;
  }
  data_container->host_data.b.resize(data_container->num_constraints);
  reset(data_container->host_data.b);

  rigid_rigid.Build_b(mode);
  bilateral.Build_b();

  data_container->host_data.R = -data_container->host_data.b - data_container->host_data.D_T * data_container->host_data.M_invk;
}

void ChLcpSolverParallelDVI::ChangeSolverType(SOLVERTYPE type) {
  data_container->settings.solver.solver_type = type;

  if (this->solver) {
    delete (this->solver);
  }
  if (type == STEEPEST_DESCENT) {
    solver = new ChSolverSD();
  } else if (type == GRADIENT_DESCENT) {
    solver = new ChSolverGD();
  } else if (type == CONJUGATE_GRADIENT) {
    solver = new ChSolverCG();
  } else if (type == CONJUGATE_GRADIENT_SQUARED) {
    solver = new ChSolverCGS();
  } else if (type == BICONJUGATE_GRADIENT) {
    solver = new ChSolverBiCG();
  } else if (type == BICONJUGATE_GRADIENT_STAB) {
    solver = new ChSolverBiCGStab();
  } else if (type == MINIMUM_RESIDUAL) {
    solver = new ChSolverMinRes();
  } else if (type == QUASAI_MINIMUM_RESIDUAL) {
    //         // This solver has not been implemented yet
    //         //SolveQMR(data_container->gpu_data.device_gam_data, rhs, max_iteration);
  } else if (type == APGD) {
    solver = new ChSolverAPGD();
  } else if (type == APGDREF) {
    solver = new ChSolverAPGDREF();
  } else if (type == JACOBI) {
    solver = new ChSolverJacobi();
  } else if (type == GAUSS_SEIDEL) {
    solver = new ChSolverPGS();
  } else if (type == PDIP) {
    solver = new ChSolverPDIP();
  }
}
<|endoftext|>


<commit_before><commit_msg>[User Interface] IDEA-75238 Microsoft Windows Jump Lists support: disable explicit AppUserModelId.<commit_after><|endoftext|>


<commit_before>/** @file saw.cc
 * Implement a self-avoiding (random) walk.
 */
#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>

#include "point.h"

typedef std::vector<Point> Walk;
typedef std::mt19937 RandomEngine;

/** Check if a new point is legal in the context of a walk.
 * It is actually not necessary to check the whole vector. The position of the
 * new point is known and afterwards only (0, 0)s follow. This is clearly
 * something that could be optimised...
 * @param w the (partial) walk, that p is to be added to
 * @param p the new point
 * @return whether p is legal in the context of w
 */
bool IsLegalPoint(const Walk &w, const Point &p) {
  return std::find(std::begin(w), std::end(w), p) == std::end(w);
}

/** Construct a new self-avoiding random walk on a given vector of given size.
 * The function is called recursively until the vector is full.
 * @param step the current step
 * @param walk reference to a container in which the walk is stored
 * @param rand the random engine used for generating random numbers
 * @return true if a SAW was constructed, false if not
 */
bool SelfAvoidingWalk(const size_t step,  Walk &walk, RandomEngine &rand) {
  if (step == walk.size()) {
    return true;  // yay! we found a legal SAW
  }
  std::vector<Point> directions{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
  std::shuffle(std::begin(directions), std::end(directions), rand);
  for (const Point &direction : directions) {
    Point new_point(walk[step - 1] + direction);
    if (IsLegalPoint(walk, new_point)) {
      walk[step] = walk[step - 1] + direction;
      if (SelfAvoidingWalk(step + 1, walk, rand)) {
        return true;  // we're done here and can go home
      }  // otherwise we have to try the next direction
    }
  }
  return false;  // if no direction succeeded, we return home shamefully
}

/** Calculate R_N^2 for a given walk.
 * @param the walk
 * @return R_N^2, the average cluster size squared
 */
double CalculateAverageClusterSizeSquared(const Walk &walk) {
  std::vector<Point> directions{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
  Walk test_walk(walk.size());
  double walk_weight(1.0);
  std::for_each(std::begin(walk), std::end(walk),
                [&](const Point p){
                  double single_weight(0.0);
                  test_walk.push_back(p);
                  for(const Point &direction : directions) {
                    Point new_point(p + direction);
                    if (IsLegalPoint(test_walk, new_point)) { ++single_weight; };
                  }
                  walk_weight = walk_weight * single_weight > 0.0 ? walk_weight * single_weight : 1.0;
                });
  return 1.0 / (walk_weight * walk_weight) * walk.back().Squared();
}

int main(int argc, char *argv[]) {
  // set up random number generator
  std::random_device rd;
  std::mt19937 rng(rd());
  // calculate average cluster size for SAWs of varying lengths
  std::vector<double> RN2s(1000000);
  size_t N;
  double mean,
         sem;
  for (N = 20; N <= 60; N += 5) {
    Walk walk(N);
    std::generate(std::begin(RN2s), std::end(RN2s), [&]() {
      std::fill(std::begin(walk), std::end(walk), Point{0, 0});
      while(!SelfAvoidingWalk(1, walk, rng)) {}  // make sure we have a SAW
      return CalculateAverageClusterSizeSquared(walk);
    });
    mean = std::accumulate(std::begin(RN2s), std::end(RN2s), 0.0)
           / RN2s.size();
    sem = sqrt(std::accumulate(std::begin(RN2s), std::end(RN2s), 0.0,
                          [&](const double acc, const double x) {
                            return acc + (x - mean) * (x - mean);
                          })) / RN2s.size();  // N(N-1) ~ N^2 here
    std::cout << N << " " << mean << " " << sem << std::endl;
  }
}
<commit_msg>less walks<commit_after>/** @file saw.cc
 * Implement a self-avoiding (random) walk.
 */
#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>

#include "point.h"

typedef std::vector<Point> Walk;
typedef std::mt19937 RandomEngine;

/** Check if a new point is legal in the context of a walk.
 * It is actually not necessary to check the whole vector. The position of the
 * new point is known and afterwards only (0, 0)s follow. This is clearly
 * something that could be optimised...
 * @param w the (partial) walk, that p is to be added to
 * @param p the new point
 * @return whether p is legal in the context of w
 */
bool IsLegalPoint(const Walk &w, const Point &p) {
  return std::find(std::begin(w), std::end(w), p) == std::end(w);
}

/** Construct a new self-avoiding random walk on a given vector of given size.
 * The function is called recursively until the vector is full.
 * @param step the current step
 * @param walk reference to a container in which the walk is stored
 * @param rand the random engine used for generating random numbers
 * @return true if a SAW was constructed, false if not
 */
bool SelfAvoidingWalk(const size_t step,  Walk &walk, RandomEngine &rand) {
  if (step == walk.size()) {
    return true;  // yay! we found a legal SAW
  }
  std::vector<Point> directions{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
  std::shuffle(std::begin(directions), std::end(directions), rand);
  for (const Point &direction : directions) {
    Point new_point(walk[step - 1] + direction);
    if (IsLegalPoint(walk, new_point)) {
      walk[step] = walk[step - 1] + direction;
      if (SelfAvoidingWalk(step + 1, walk, rand)) {
        return true;  // we're done here and can go home
      }  // otherwise we have to try the next direction
    }
  }
  return false;  // if no direction succeeded, we return home shamefully
}

/** Calculate R_N^2 for a given walk.
 * @param the walk
 * @return R_N^2, the average cluster size squared
 */
double CalculateAverageClusterSizeSquared(const Walk &walk) {
  std::vector<Point> directions{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
  Walk test_walk(walk.size());
  double walk_weight(1.0);
  std::for_each(std::begin(walk), std::end(walk),
                [&](const Point p){
                  double single_weight(0.0);
                  test_walk.push_back(p);
                  for(const Point &direction : directions) {
                    Point new_point(p + direction);
                    if (IsLegalPoint(test_walk, new_point)) { ++single_weight; };
                  }
                  walk_weight = walk_weight * single_weight > 0.0 ? walk_weight * single_weight : 1.0;
                });
  return 1.0 / (walk_weight * walk_weight) * walk.back().Squared();
}

int main(int argc, char *argv[]) {
  // set up random number generator
  std::random_device rd;
  std::mt19937 rng(rd());
  // calculate average cluster size for SAWs of varying lengths
  std::vector<double> RN2s(100000);
  size_t N;
  double mean,
         sem;
  for (N = 20; N <= 60; N += 5) {
    Walk walk(N);
    std::generate(std::begin(RN2s), std::end(RN2s), [&]() {
      std::fill(std::begin(walk), std::end(walk), Point{0, 0});
      while(!SelfAvoidingWalk(1, walk, rng)) {}  // make sure we have a SAW
      return CalculateAverageClusterSizeSquared(walk);
    });
    mean = std::accumulate(std::begin(RN2s), std::end(RN2s), 0.0)
           / RN2s.size();
    sem = sqrt(std::accumulate(std::begin(RN2s), std::end(RN2s), 0.0,
                          [&](const double acc, const double x) {
                            return acc + (x - mean) * (x - mean);
                          })) / RN2s.size();  // N(N-1) ~ N^2 here
    std::cout << N << " " << mean << " " << sem << std::endl;
  }
}
<|endoftext|>


<commit_before>// Copyright 2017 Netherlands Institute for Radio Astronomy (ASTRON)
// Copyright 2017 Netherlands eScience Center
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <configuration.hpp>
#include <CommandLine.hpp>
#include <Kernels.hpp>
#include <Memory.hpp>
#include <Pipeline.hpp>

int main(int argc, char * argv[]) {
  // Command line options
  Options options {};
  DeviceOptions deviceOptions {};
  DataOptions dataOptions {};
  GeneratorOptions generatorOptions {};
  // Memory
  HostMemory hostMemory {};
  DeviceMemory deviceMemory {};
  // OpenCL kernels
  OpenCLRunTime openclRunTime {};
  KernelConfigurations kernelConfigurations {};
  Kernels kernels {};
  KernelRunTimeConfigurations kernelRunTimeConfigurations {};
  // Timers
  Timers timers {};
  // Observation
  AstroData::Observation observation;

  // Process command line arguments
  isa::utils::ArgumentList args(argc, argv);
  try {
    processCommandLineOptions(args, options, deviceOptions, dataOptions, kernelConfigurations, generatorOptions,
                              observation);
  } catch ( std::exception & err ) {
    return 1;
  }

  // Load or generate input data
  try {
    hostMemory.zappedChannels.resize(observation.getNrChannels(deviceOptions.padding.at(deviceOptions.deviceName)
                                                                   / sizeof(unsigned int)));
    try {
      AstroData::readZappedChannels(observation, dataOptions.channelsFile, hostMemory.zappedChannels);
      AstroData::readIntegrationSteps(observation, dataOptions.integrationFile, hostMemory.integrationSteps);
    } catch ( AstroData::FileError & err ) {
      std::cerr << err.what() << std::endl;
      throw;
    }
    hostMemory.input.resize(observation.getNrBeams());
    if ( dataOptions.dataLOFAR || dataOptions.dataSIGPROC || dataOptions.dataPSRDADA ) {
      loadInput(observation, deviceOptions, dataOptions, hostMemory, timers);
    } else {
      for ( unsigned int beam = 0; beam < observation.getNrBeams(); beam++ ) {
        // TODO: if there are multiple synthesized beams, the generated data should take this into account
        hostMemory.input.at(beam) = new std::vector<std::vector<inputDataType> *>(observation.getNrBatches());
        AstroData::generateSinglePulse(generatorOptions.width, generatorOptions.DM, observation,
                                       deviceOptions.padding.at(deviceOptions.deviceName),
                                       *(hostMemory.input.at(beam)), inputBits, generatorOptions.random);
      }
    }
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Print message with observation and search information
  if ( options.print) {
    std::cout << "Device: " << deviceOptions.deviceName << "(" + std::to_string(deviceOptions.platformID) +  ", ";
    std::cout << std::to_string(deviceOptions.deviceID) + ")" << std::endl;
    std::cout << "Padding: " << deviceOptions.padding[deviceOptions.deviceName] << " bytes" << std::endl;
    std::cout << std::endl;
    std::cout << "Beams: " << observation.getNrBeams() << std::endl;
    std::cout << "Synthesized Beams: " << observation.getNrSynthesizedBeams() << std::endl;
    std::cout << "Batches: " << observation.getNrBatches() << std::endl;
    std::cout << "Samples: " << observation.getNrSamplesPerBatch() << std::endl;
    std::cout << "Sampling time: " << observation.getSamplingTime() << std::endl;
    std::cout << "Frequency range: " << observation.getMinFreq() << " MHz, " << observation.getMaxFreq() << " MHz";
    std::cout << std::endl;
    std::cout << "Subbands: " << observation.getNrSubbands() << " (" << observation.getSubbandBandwidth() << " MHz)";
    std::cout << std::endl;
    std::cout << "Channels: " << observation.getNrChannels() << " (" << observation.getChannelBandwidth() << " MHz)";
    std::cout << std::endl;
    std::cout << "Zapped Channels: " << observation.getNrZappedChannels() << std::endl;
    std::cout << "Integration steps: " << hostMemory.integrationSteps.size() << std::endl;
    if ( options.subbandDedispersion ) {
      std::cout << "Subbanding DMs: " << observation.getNrDMs(true) << " (" << observation.getFirstDM(true) << ", ";
      std::cout << observation.getFirstDM(true) + ((observation.getNrDMs(true) - 1) * observation.getDMStep(true));
      std::cout << ")" << std::endl;
    }
    std::cout << "DMs: " << observation.getNrDMs() << " (" << observation.getFirstDM() << ", ";
    std::cout << observation.getFirstDM() + ((observation.getNrDMs() - 1) * observation.getDMStep()) << ")";
    std::cout << std::endl;
    std::cout << std::endl;
  }

  // Initialize OpenCL
  openclRunTime.context = new cl::Context();
  openclRunTime.platforms = new std::vector<cl::Platform>();
  openclRunTime.devices = new std::vector<cl::Device>();
  openclRunTime.queues = new std::vector<std::vector<cl::CommandQueue>>();
  try {
    isa::OpenCL::initializeOpenCL(deviceOptions.platformID, 1, openclRunTime.platforms, openclRunTime.context,
                                  openclRunTime.devices, openclRunTime.queues);
  } catch ( isa::OpenCL::OpenCLError & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Memory allocation
  allocateHostMemory(observation, options, deviceOptions, kernelConfigurations, hostMemory);
  if ( observation.getNrDelayBatches() > observation.getNrBatches() ) {
    std::cerr << "Not enough input batches for the specified search." << std::endl;
    return 1;
  }
  try {
    allocateDeviceMemory(openclRunTime, options, deviceOptions, hostMemory, deviceMemory);
  } catch ( cl::Error & err ) {
    std::cerr << "Memory error: " << err.what() << " " << err.err() << std::endl;
    return 1;
  }

  // Generate OpenCL kernels
  try {
    generateOpenCLKernels(openclRunTime, observation, options, deviceOptions, kernelConfigurations, hostMemory,
                          deviceMemory, kernels);
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Generate run time configurations for the OpenCL kernels
  generateOpenCLRunTimeConfigurations(observation, options, deviceOptions, kernelConfigurations, hostMemory,
                                      kernelRunTimeConfigurations);

  // Search loop
  pipeline(openclRunTime, observation, options, deviceOptions, dataOptions, timers, kernels, kernelConfigurations,
           kernelRunTimeConfigurations, hostMemory, deviceMemory);

  // Store performance statistics before shutting down
  std::ofstream outputStats;
  outputStats.open(dataOptions.outputFile + ".stats");
  outputStats << std::fixed << std::setprecision(6);
  outputStats << "# nrDMs" << std::endl;
  if ( options.subbandDedispersion ) {
    outputStats << observation.getNrDMs(true) * observation.getNrDMs() << std::endl;
  } else {
    outputStats << observation.getNrDMs() << std::endl;
  }
  outputStats << "# timers.inputLoad" << std::endl;
  outputStats << timers.inputLoad.getTotalTime() << std::endl;
  outputStats << "# timers.search" << std::endl;
  outputStats << timers.search.getTotalTime() << std::endl;
  outputStats << "# inputHandlingTotal inputHandlingAvg err" << std::endl;
  outputStats << timers.inputHandling.getTotalTime() << " " << timers.inputHandling.getAverageTime() << " ";
  outputStats << timers.inputHandling.getStandardDeviation() << std::endl;
  outputStats << "# inputCopyTotal inputCopyAvg err" << std::endl;
  outputStats << timers.inputCopy.getTotalTime() << " " << timers.inputCopy.getAverageTime() << " ";
  outputStats << timers.inputCopy.getStandardDeviation() << std::endl;
  if ( ! options.subbandDedispersion ) {
    outputStats << "# dedispersionSingleStepTotal dedispersionSingleStepAvg err" << std::endl;
    outputStats << timers.dedispersionSingleStep.getTotalTime() << " ";
    outputStats << timers.dedispersionSingleStep.getAverageTime() << " ";
    outputStats << timers.dedispersionSingleStep.getStandardDeviation() << std::endl;
  } else {
    outputStats << "# dedispersionStepOneTotal dedispersionStepOneAvg err" << std::endl;
    outputStats << timers.dedispersionStepOne.getTotalTime() << " ";
    outputStats << timers.dedispersionStepOne.getAverageTime() << " ";
    outputStats << timers.dedispersionStepOne.getStandardDeviation() << std::endl;
    outputStats << "# dedispersionStepTwoTotal dedispersionStepTwoAvg err" << std::endl;
    outputStats << timers.dedispersionStepTwo.getTotalTime() << " ";
    outputStats << timers.dedispersionStepTwo.getAverageTime() << " ";
    outputStats << timers.dedispersionStepTwo.getStandardDeviation() << std::endl;
  }
  outputStats << "# integrationTotal integrationAvg err" << std::endl;
  outputStats << timers.integration.getTotalTime() << " " << timers.integration.getAverageTime() << " ";
  outputStats << timers.integration.getStandardDeviation() << std::endl;
  outputStats << "# snrTotal snrAvg err" << std::endl;
  outputStats << timers.snr.getTotalTime() << " " << timers.snr.getAverageTime() << " ";
  outputStats << timers.snr.getStandardDeviation() << std::endl;
  outputStats << "# outputCopyTotal outputCopyAvg err" << std::endl;
  outputStats << timers.outputCopy.getTotalTime() << " " << timers.outputCopy.getAverageTime() << " ";
  outputStats << timers.outputCopy.getStandardDeviation() << std::endl;
  outputStats << "# triggerTimeTotal triggerTimeAvg err" << std::endl;
  outputStats << timers.trigger.getTotalTime() << " " << timers.trigger.getAverageTime() << " ";
  outputStats << timers.trigger.getStandardDeviation() << std::endl;
  outputStats.close();

  return 0;
}

<commit_msg>Added check padding.<commit_after>// Copyright 2017 Netherlands Institute for Radio Astronomy (ASTRON)
// Copyright 2017 Netherlands eScience Center
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <configuration.hpp>
#include <CommandLine.hpp>
#include <Kernels.hpp>
#include <Memory.hpp>
#include <Pipeline.hpp>

int main(int argc, char * argv[]) {
  // Command line options
  Options options {};
  DeviceOptions deviceOptions {};
  DataOptions dataOptions {};
  GeneratorOptions generatorOptions {};
  // Memory
  HostMemory hostMemory {};
  DeviceMemory deviceMemory {};
  // OpenCL kernels
  OpenCLRunTime openclRunTime {};
  KernelConfigurations kernelConfigurations {};
  Kernels kernels {};
  KernelRunTimeConfigurations kernelRunTimeConfigurations {};
  // Timers
  Timers timers {};
  // Observation
  AstroData::Observation observation;

  // Process command line arguments
  isa::utils::ArgumentList args(argc, argv);
  try {
    processCommandLineOptions(args, options, deviceOptions, dataOptions, kernelConfigurations, generatorOptions,
                              observation);
  } catch ( std::exception & err ) {
    return 1;
  }

  // Load or generate input data
  try {
    try {
      hostMemory.zappedChannels.resize(observation.getNrChannels(deviceOptions.padding.at(deviceOptions.deviceName)
                                                                 / sizeof(unsigned int)));
    } catch ( std::out_of_range & err ) {
      std::cerr << "No padding specified for " << deviceOptions.deviceName << "." << std::endl;
      return 1;
    }
    try {
      AstroData::readZappedChannels(observation, dataOptions.channelsFile, hostMemory.zappedChannels);
      AstroData::readIntegrationSteps(observation, dataOptions.integrationFile, hostMemory.integrationSteps);
    } catch ( AstroData::FileError & err ) {
      std::cerr << err.what() << std::endl;
      return 1;
    }
    hostMemory.input.resize(observation.getNrBeams());
    if ( dataOptions.dataLOFAR || dataOptions.dataSIGPROC || dataOptions.dataPSRDADA ) {
      loadInput(observation, deviceOptions, dataOptions, hostMemory, timers);
    } else {
      for ( unsigned int beam = 0; beam < observation.getNrBeams(); beam++ ) {
        // TODO: if there are multiple synthesized beams, the generated data should take this into account
        hostMemory.input.at(beam) = new std::vector<std::vector<inputDataType> *>(observation.getNrBatches());
        AstroData::generateSinglePulse(generatorOptions.width, generatorOptions.DM, observation,
                                       deviceOptions.padding.at(deviceOptions.deviceName),
                                       *(hostMemory.input.at(beam)), inputBits, generatorOptions.random);
      }
    }
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Print message with observation and search information
  if ( options.print) {
    std::cout << "Device: " << deviceOptions.deviceName << "(" + std::to_string(deviceOptions.platformID) +  ", ";
    std::cout << std::to_string(deviceOptions.deviceID) + ")" << std::endl;
    std::cout << "Padding: " << deviceOptions.padding[deviceOptions.deviceName] << " bytes" << std::endl;
    std::cout << std::endl;
    std::cout << "Beams: " << observation.getNrBeams() << std::endl;
    std::cout << "Synthesized Beams: " << observation.getNrSynthesizedBeams() << std::endl;
    std::cout << "Batches: " << observation.getNrBatches() << std::endl;
    std::cout << "Samples: " << observation.getNrSamplesPerBatch() << std::endl;
    std::cout << "Sampling time: " << observation.getSamplingTime() << std::endl;
    std::cout << "Frequency range: " << observation.getMinFreq() << " MHz, " << observation.getMaxFreq() << " MHz";
    std::cout << std::endl;
    std::cout << "Subbands: " << observation.getNrSubbands() << " (" << observation.getSubbandBandwidth() << " MHz)";
    std::cout << std::endl;
    std::cout << "Channels: " << observation.getNrChannels() << " (" << observation.getChannelBandwidth() << " MHz)";
    std::cout << std::endl;
    std::cout << "Zapped Channels: " << observation.getNrZappedChannels() << std::endl;
    std::cout << "Integration steps: " << hostMemory.integrationSteps.size() << std::endl;
    if ( options.subbandDedispersion ) {
      std::cout << "Subbanding DMs: " << observation.getNrDMs(true) << " (" << observation.getFirstDM(true) << ", ";
      std::cout << observation.getFirstDM(true) + ((observation.getNrDMs(true) - 1) * observation.getDMStep(true));
      std::cout << ")" << std::endl;
    }
    std::cout << "DMs: " << observation.getNrDMs() << " (" << observation.getFirstDM() << ", ";
    std::cout << observation.getFirstDM() + ((observation.getNrDMs() - 1) * observation.getDMStep()) << ")";
    std::cout << std::endl;
    std::cout << std::endl;
  }

  // Initialize OpenCL
  openclRunTime.context = new cl::Context();
  openclRunTime.platforms = new std::vector<cl::Platform>();
  openclRunTime.devices = new std::vector<cl::Device>();
  openclRunTime.queues = new std::vector<std::vector<cl::CommandQueue>>();
  try {
    isa::OpenCL::initializeOpenCL(deviceOptions.platformID, 1, openclRunTime.platforms, openclRunTime.context,
                                  openclRunTime.devices, openclRunTime.queues);
  } catch ( isa::OpenCL::OpenCLError & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Memory allocation
  allocateHostMemory(observation, options, deviceOptions, kernelConfigurations, hostMemory);
  if ( observation.getNrDelayBatches() > observation.getNrBatches() ) {
    std::cerr << "Not enough input batches for the specified search." << std::endl;
    return 1;
  }
  try {
    allocateDeviceMemory(openclRunTime, options, deviceOptions, hostMemory, deviceMemory);
  } catch ( cl::Error & err ) {
    std::cerr << "Memory error: " << err.what() << " " << err.err() << std::endl;
    return 1;
  }

  // Generate OpenCL kernels
  try {
    generateOpenCLKernels(openclRunTime, observation, options, deviceOptions, kernelConfigurations, hostMemory,
                          deviceMemory, kernels);
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Generate run time configurations for the OpenCL kernels
  generateOpenCLRunTimeConfigurations(observation, options, deviceOptions, kernelConfigurations, hostMemory,
                                      kernelRunTimeConfigurations);

  // Search loop
  pipeline(openclRunTime, observation, options, deviceOptions, dataOptions, timers, kernels, kernelConfigurations,
           kernelRunTimeConfigurations, hostMemory, deviceMemory);

  // Store performance statistics before shutting down
  std::ofstream outputStats;
  outputStats.open(dataOptions.outputFile + ".stats");
  outputStats << std::fixed << std::setprecision(6);
  outputStats << "# nrDMs" << std::endl;
  if ( options.subbandDedispersion ) {
    outputStats << observation.getNrDMs(true) * observation.getNrDMs() << std::endl;
  } else {
    outputStats << observation.getNrDMs() << std::endl;
  }
  outputStats << "# timers.inputLoad" << std::endl;
  outputStats << timers.inputLoad.getTotalTime() << std::endl;
  outputStats << "# timers.search" << std::endl;
  outputStats << timers.search.getTotalTime() << std::endl;
  outputStats << "# inputHandlingTotal inputHandlingAvg err" << std::endl;
  outputStats << timers.inputHandling.getTotalTime() << " " << timers.inputHandling.getAverageTime() << " ";
  outputStats << timers.inputHandling.getStandardDeviation() << std::endl;
  outputStats << "# inputCopyTotal inputCopyAvg err" << std::endl;
  outputStats << timers.inputCopy.getTotalTime() << " " << timers.inputCopy.getAverageTime() << " ";
  outputStats << timers.inputCopy.getStandardDeviation() << std::endl;
  if ( ! options.subbandDedispersion ) {
    outputStats << "# dedispersionSingleStepTotal dedispersionSingleStepAvg err" << std::endl;
    outputStats << timers.dedispersionSingleStep.getTotalTime() << " ";
    outputStats << timers.dedispersionSingleStep.getAverageTime() << " ";
    outputStats << timers.dedispersionSingleStep.getStandardDeviation() << std::endl;
  } else {
    outputStats << "# dedispersionStepOneTotal dedispersionStepOneAvg err" << std::endl;
    outputStats << timers.dedispersionStepOne.getTotalTime() << " ";
    outputStats << timers.dedispersionStepOne.getAverageTime() << " ";
    outputStats << timers.dedispersionStepOne.getStandardDeviation() << std::endl;
    outputStats << "# dedispersionStepTwoTotal dedispersionStepTwoAvg err" << std::endl;
    outputStats << timers.dedispersionStepTwo.getTotalTime() << " ";
    outputStats << timers.dedispersionStepTwo.getAverageTime() << " ";
    outputStats << timers.dedispersionStepTwo.getStandardDeviation() << std::endl;
  }
  outputStats << "# integrationTotal integrationAvg err" << std::endl;
  outputStats << timers.integration.getTotalTime() << " " << timers.integration.getAverageTime() << " ";
  outputStats << timers.integration.getStandardDeviation() << std::endl;
  outputStats << "# snrTotal snrAvg err" << std::endl;
  outputStats << timers.snr.getTotalTime() << " " << timers.snr.getAverageTime() << " ";
  outputStats << timers.snr.getStandardDeviation() << std::endl;
  outputStats << "# outputCopyTotal outputCopyAvg err" << std::endl;
  outputStats << timers.outputCopy.getTotalTime() << " " << timers.outputCopy.getAverageTime() << " ";
  outputStats << timers.outputCopy.getStandardDeviation() << std::endl;
  outputStats << "# triggerTimeTotal triggerTimeAvg err" << std::endl;
  outputStats << timers.trigger.getTotalTime() << " " << timers.trigger.getAverageTime() << " ";
  outputStats << timers.trigger.getStandardDeviation() << std::endl;
  outputStats.close();

  return 0;
}

<|endoftext|>