<commit_before>/* Copyright 2016-2017 CyberTech Labs Ltd.
 *
 * 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 <QtCore/QTimer>
#include <QtCore/QEventLoop>

#include <QtCore/QThread>

#include <trikKitInterpreterCommon/trikbrick.h>

#include <utils/abstractTimer.h>
#include <kitBase/robotModel/robotModelUtils.h>
#include <trikKit/robotModel/parts/trikShell.h>
#include <trikKit/robotModel/parts/trikLineSensor.h>
#include <kitBase/robotModel/robotParts/gyroscopeSensor.h>
#include <kitBase/robotModel/robotParts/encoderSensor.h>
#include <kitBase/robotModel/robotParts/random.h>
#include <kitBase/robotModel/robotParts/random.h>
#include <twoDModel/robotModel/parts/marker.h>
#include <twoDModel/engine/model/timeline.h>
///todo: temporary
#include <trikKitInterpreterCommon/robotModel/twoD/parts/twoDDisplay.h>

using namespace trik;

TrikBrick::TrikBrick(const QSharedPointer<robotModel::twoD::TrikTwoDRobotModel> &model)
	: mTwoDRobotModel(model)
	, mDisplay(model)
	, mKeys(model)
	, mSensorUpdater(model->timeline().produceTimer())
{
	connect(this, &TrikBrick::log, this, &TrikBrick::printToShell);
	mSensorUpdater->setRepeatable(true);
	mSensorUpdater->setInterval(model->updateIntervalForInterpretation()); // seems to be x2 of timeline tick
	connect(mSensorUpdater.data(), &utils::AbstractTimer::timeout, [model](){
		model->updateSensorsValues(); /// @todo: maybe connect to model directly?
	});
}

TrikBrick::~TrikBrick()
{
	qDeleteAll(mMotors);
	qDeleteAll(mSensors);
	qDeleteAll(mEncoders);
	qDeleteAll(mLineSensors);
	qDeleteAll(mTimers);
}

void TrikBrick::reset()
{
	mKeys.reset();///@todo: reset motos/device maps?
	//mDisplay.reset(); - is actually needed? Crashes app at exit
	emit stopWaiting();
	for (const auto &m : mMotors) {
		m->powerOff();
	}
	for (const auto &e : mEncoders) {
		e->reset();
	}
	for (const auto &t : mTimers) {
		t->stop();
	}
	qDeleteAll(mTimers);
	mTimers.clear();
	QMetaObject::invokeMethod(mSensorUpdater.data(), "stop"); // failproof against timer manipulation in another thread
}

void TrikBrick::printToShell(const QString &msg)
{
	using namespace kitBase::robotModel;
	using namespace trik::robotModel;
	parts::TrikShell* sh = RobotModelUtils::findDevice<parts::TrikShell>(*mTwoDRobotModel, "ShellPort");
	if (sh == nullptr) {
		qDebug("Error: 2d model shell part was not found");
		return;
	}
	sh->print(msg);
}

void TrikBrick::init()
{
	mDisplay.init();
//	for (const auto &m : mMotors) {
//		m->powerOff();
//	}
//	for (const auto &e : mEncoders) {
//		e->read();
//	}
//	for (const auto &s : mSensors) {
//		s->read();
//	}
	mTwoDRobotModel->updateSensorsValues();
	mMotors.clear(); // needed? reset?
	mSensors.clear();
	mEncoders.clear();
	mKeys.init();
	mGyroscope.reset(); // for some reason it won't reconnect to the robot parts otherwise.
	QMetaObject::invokeMethod(mSensorUpdater.data(), "start"); // failproof against timer manipulation in another thread
	//mSensorUpdater.start();
}

void TrikBrick::setCurrentDir(const QString &dir)
{
	mCurrentDir = QFileInfo(dir).dir(); // maybe can be constructed directly
}

void TrikBrick::setCurrentInputs(const QString &f)
{
	mIsExcerciseMode = true;
	if (f.isEmpty()) {
		return; // no inputs has been passed, no need to complain
	}
	QString file(f);
	QFile in(file);
	if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
		emit warning(tr("Trying to read from file %1 failed").arg(file)); // todo: remove? It's only in exercise.
		//not really an error, usually
	}

	QStringList result;

	while (!in.atEnd()) {
		const auto line = in.readLine();
		result << QString::fromUtf8(line);
	}

	mInputs = result;
}

void TrikBrick::say(const QString &msg) {
	using namespace kitBase::robotModel;
	using namespace trik::robotModel;
	parts::TrikShell* sh = RobotModelUtils::findDevice<parts::TrikShell>(*mTwoDRobotModel, "ShellPort");
	if (sh == nullptr) {
		qDebug("Error: 2d model shell part was not found");
		return;
	}
	QMetaObject::invokeMethod(sh, "say", Q_ARG(const QString &, msg));
}

void TrikBrick::stop() {
	/// @todo: properly implement this?
	mTwoDRobotModel->stopRobot();
//	for (const auto &m : mMotors) {
//		m->powerOff();
//	}
//	for (const auto &e : mEncoders) {
//		e->reset();
//	}
}

trikControl::MotorInterface *TrikBrick::motor(const QString &port)
{
	using namespace kitBase::robotModel;
	if (!mMotors.contains(port)) {
		robotParts::Motor * mot =
				RobotModelUtils::findDevice<robotParts::Motor>(*mTwoDRobotModel, port);
		if (mot == nullptr) {
			emit error(tr("No configured motor on port: %1").arg(port));
			return nullptr;
		}
		mMotors[port] = new TrikMotorEmu(mot);
	}
	return mMotors[port];
}

trikControl::MarkerInterface *TrikBrick::marker()
{
	kitBase::robotModel::PortInfo markerPort = kitBase::robotModel::RobotModelUtils::findPort(*mTwoDRobotModel
			, "MarkerPort"
			, kitBase::robotModel::Direction::output);
	if (markerPort.isValid()) {
		using Marker = twoDModel::robotModel::parts::Marker;
		Marker* marker = kitBase::robotModel::RobotModelUtils::findDevice<Marker>(*mTwoDRobotModel, markerPort);
		mTrikProxyMarker.reset(new TrikProxyMarker(marker));
		return mTrikProxyMarker.data();
	}

	return nullptr;
}

trikControl::SensorInterface *TrikBrick::sensor(const QString &port)
{
	//testing
	using namespace kitBase::robotModel;
	if (!mSensors.contains(port)) {
		robotParts::ScalarSensor * sens =
				RobotModelUtils::findDevice<robotParts::ScalarSensor>(*mTwoDRobotModel, port);
		if (sens == nullptr) {
			emit error(tr("No configured sensor on port: %1").arg(port));
			return nullptr;
		}
		mSensors[port] = new TrikSensorEmu(sens);
	}
	return mSensors[port];
}

QStringList TrikBrick::motorPorts(trikControl::MotorInterface::Type type) const
{
	Q_UNUSED(type)
//	QLOG_INFO() << "Motor type is ignored";
	return mMotors.keys();
}

QStringList TrikBrick::sensorPorts(trikControl::SensorInterface::Type type) const
{
	Q_UNUSED(type)
//	QLOG_INFO() << "Sensor type is ignored";
	return mMotors.keys();
}

QStringList TrikBrick::encoderPorts() const {
	return mEncoders.keys();
}

trikControl::VectorSensorInterface *TrikBrick::accelerometer() {
	using namespace kitBase::robotModel;
	if (mAccelerometer.isNull()) {
		auto a = RobotModelUtils::findDevice<robotParts::AccelerometerSensor>(*mTwoDRobotModel
				, "AccelerometerPort");
		if (a == nullptr) {
			emit error(tr("No configured accelerometer"));
			return nullptr;
		}
		mAccelerometer.reset(new TrikAccelerometerAdapter(a));
	}

	return mAccelerometer.data();
}

trikControl::GyroSensorInterface *TrikBrick::gyroscope() {
	using namespace kitBase::robotModel;
	if (mGyroscope.isNull()) {
		auto a = RobotModelUtils::findDevice<robotParts::GyroscopeSensor>(*mTwoDRobotModel
				, "GyroscopePort");
		if (a == nullptr) {
			emit error(tr("No configured gyroscope"));
			return nullptr;
		}
		mGyroscope.reset(new TrikGyroscopeAdapter(a, mTwoDRobotModel));
	}

	return mGyroscope.data();
}

trikControl::LineSensorInterface *TrikBrick::lineSensor(const QString &port) {
	using namespace trik::robotModel::parts;
	using namespace kitBase::robotModel;
	if (port == "video0") {
		return lineSensor("LineSensorPort"); // seems to be the case for 2d model
	}

	if (!mLineSensors.contains(port)) {
		TrikLineSensor * sens =
				RobotModelUtils::findDevice<TrikLineSensor>(*mTwoDRobotModel, port);
		if (sens == nullptr) {
			emit error(tr("No configured LineSensor on port: %1").arg(port));
			return nullptr;
		}
		mLineSensors[port] = new TrikLineSensorAdapter(sens);
	}

	return mLineSensors[port];
}

trikControl::EncoderInterface *TrikBrick::encoder(const QString &port) {
	using namespace kitBase::robotModel;
	if (!mEncoders.contains(port)) {
		robotParts::EncoderSensor * enc =
				RobotModelUtils::findDevice<robotParts::EncoderSensor>(*mTwoDRobotModel, port);
		if (enc == nullptr) {
			emit error(tr("No configured encoder on port: %1").arg(port));
			return nullptr;
		}

		mEncoders[port] = new TrikEncoderAdapter(enc->port(), mTwoDRobotModel->engine());
	}

	return mEncoders[port];
}

trikControl::DisplayInterface *TrikBrick::display()
{
//	trik::robotModel::parts::TrikDisplay * const display =
//			kitBase::robotModel::RobotModelUtils::findDevice<trik::robotModel::parts::TrikDisplay>(*mTwoDRobotModel
//					, "DisplayPort");
//	if (display) {
//		bool res = QMetaObject::invokeMethod(display,
//		"drawSmile",
//		Qt::QueuedConnection, // connection type, auto?
//		Q_ARG(bool, false));
//		//display->drawSmile(false);
//		printf(res ? "true" : "false");
//	}
//	return nullptr;
	return &mDisplay;
}

trikControl::LedInterface *TrikBrick::led() {
	using namespace trik::robotModel::parts;
	using namespace kitBase::robotModel;
	if (mLed.isNull()) {
		auto l = RobotModelUtils::findDevice<TrikLed>(*mTwoDRobotModel, "LedPort");
		if (l == nullptr) {
			emit error(tr("No configured led"));
			return nullptr;
		}
		mLed.reset(new TrikLedAdapter(l));
	}

	return mLed.data();
}

int TrikBrick::random(int from, int to)
{
	using namespace kitBase::robotModel;
	auto r = RobotModelUtils::findDevice<robotParts::Random>(*mTwoDRobotModel, "RandomPort");
	// maybe store it later, like the others
	if (!r) {
		emit error(tr("No cofigured random device"));
		return -1;
	}

	return r->random(from, to);
}

void TrikBrick::wait(int milliseconds)
{
	auto timeline = dynamic_cast<twoDModel::model::Timeline *> (&mTwoDRobotModel->timeline());

	if (timeline->isStarted()) {
		QSharedPointer<utils::AbstractTimer> t(timeline->produceTimer());
		QTimer abortTimer;
		QMetaObject::Connection abortConnection;
		QSharedPointer<QEventLoop> loop (new QEventLoop());

		auto mainHandler = [=]() {
			disconnect(abortConnection);
			disconnect(this, &TrikBrick::stopWaiting, nullptr, nullptr);
			disconnect(timeline, &twoDModel::model::Timeline::beforeStop, nullptr, nullptr);
			disconnect(t.data(), &utils::AbstractTimer::timeout, nullptr, nullptr);
			loop->quit();
		};

		auto abortHandler = [=]() {
			if (!timeline->isStarted()) {
				mainHandler();
			}
		};

		connect(t.data(), &utils::AbstractTimer::timeout, mainHandler);
		connect(this, &TrikBrick::stopWaiting, mainHandler);

		// timers that are produced by produceTimer() doesn't use stop singal
		// be careful, one who use just utils::AbstractTimer can stuck
		connect(timeline, &twoDModel::model::Timeline::beforeStop, mainHandler);
		abortConnection = connect(&abortTimer, &QTimer::timeout, abortHandler);

		// because timer is depends on twoDModel::model::Timeline
		if (timeline->isStarted()) {
			t->start(milliseconds);
			abortTimer.start(10);
			loop->exec();
		} else {
			mainHandler();
		}
	}
}

quint64 TrikBrick::time() const
{
	return mTwoDRobotModel->timeline().timestamp();
}

QStringList TrikBrick::readAll(const QString &path)
{
	if (mIsExcerciseMode) {
		return mInputs;
	}
	//if (mCurrentDir) todo: check that the current working dir is a save dir
	QFileInfo normalizedPath(mCurrentDir.absoluteFilePath(path)); // absoluteDir?
	QString file = normalizedPath.filePath();
	QFile in(file);
	if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
		emit error(tr("Trying to read from file %1 failed").arg(file));
		return {};
	}

	QStringList result;

	while (!in.atEnd()) {
		const auto line = in.readLine();
		result << QString::fromUtf8(line);
	}

	return result;
}

utils::AbstractTimer *TrikBrick::timer(int milliseconds)
{
	utils::AbstractTimer *result = mTwoDRobotModel->timeline().produceTimer();
	mTimers.append(result);
	result->setRepeatable(true); // seems to be the case
	result->start(milliseconds);
	return result;
}

<commit_msg>"this" in connect was returned<commit_after>/* Copyright 2016-2017 CyberTech Labs Ltd.
 *
 * 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 <QtCore/QTimer>
#include <QtCore/QEventLoop>

#include <QtCore/QThread>

#include <trikKitInterpreterCommon/trikbrick.h>

#include <utils/abstractTimer.h>
#include <kitBase/robotModel/robotModelUtils.h>
#include <trikKit/robotModel/parts/trikShell.h>
#include <trikKit/robotModel/parts/trikLineSensor.h>
#include <kitBase/robotModel/robotParts/gyroscopeSensor.h>
#include <kitBase/robotModel/robotParts/encoderSensor.h>
#include <kitBase/robotModel/robotParts/random.h>
#include <kitBase/robotModel/robotParts/random.h>
#include <twoDModel/robotModel/parts/marker.h>
#include <twoDModel/engine/model/timeline.h>
///todo: temporary
#include <trikKitInterpreterCommon/robotModel/twoD/parts/twoDDisplay.h>

using namespace trik;

TrikBrick::TrikBrick(const QSharedPointer<robotModel::twoD::TrikTwoDRobotModel> &model)
	: mTwoDRobotModel(model)
	, mDisplay(model)
	, mKeys(model)
	, mSensorUpdater(model->timeline().produceTimer())
{
	connect(this, &TrikBrick::log, this, &TrikBrick::printToShell);
	mSensorUpdater->setRepeatable(true);
	mSensorUpdater->setInterval(model->updateIntervalForInterpretation()); // seems to be x2 of timeline tick
	connect(mSensorUpdater.data(), &utils::AbstractTimer::timeout, [model](){
		model->updateSensorsValues(); /// @todo: maybe connect to model directly?
	});
}

TrikBrick::~TrikBrick()
{
	qDeleteAll(mMotors);
	qDeleteAll(mSensors);
	qDeleteAll(mEncoders);
	qDeleteAll(mLineSensors);
	qDeleteAll(mTimers);
}

void TrikBrick::reset()
{
	mKeys.reset();///@todo: reset motos/device maps?
	//mDisplay.reset(); - is actually needed? Crashes app at exit
	emit stopWaiting();
	for (const auto &m : mMotors) {
		m->powerOff();
	}
	for (const auto &e : mEncoders) {
		e->reset();
	}
	for (const auto &t : mTimers) {
		t->stop();
	}
	qDeleteAll(mTimers);
	mTimers.clear();
	QMetaObject::invokeMethod(mSensorUpdater.data(), "stop"); // failproof against timer manipulation in another thread
}

void TrikBrick::printToShell(const QString &msg)
{
	using namespace kitBase::robotModel;
	using namespace trik::robotModel;
	parts::TrikShell* sh = RobotModelUtils::findDevice<parts::TrikShell>(*mTwoDRobotModel, "ShellPort");
	if (sh == nullptr) {
		qDebug("Error: 2d model shell part was not found");
		return;
	}
	sh->print(msg);
}

void TrikBrick::init()
{
	mDisplay.init();
//	for (const auto &m : mMotors) {
//		m->powerOff();
//	}
//	for (const auto &e : mEncoders) {
//		e->read();
//	}
//	for (const auto &s : mSensors) {
//		s->read();
//	}
	mTwoDRobotModel->updateSensorsValues();
	mMotors.clear(); // needed? reset?
	mSensors.clear();
	mEncoders.clear();
	mKeys.init();
	mGyroscope.reset(); // for some reason it won't reconnect to the robot parts otherwise.
	QMetaObject::invokeMethod(mSensorUpdater.data(), "start"); // failproof against timer manipulation in another thread
	//mSensorUpdater.start();
}

void TrikBrick::setCurrentDir(const QString &dir)
{
	mCurrentDir = QFileInfo(dir).dir(); // maybe can be constructed directly
}

void TrikBrick::setCurrentInputs(const QString &f)
{
	mIsExcerciseMode = true;
	if (f.isEmpty()) {
		return; // no inputs has been passed, no need to complain
	}
	QString file(f);
	QFile in(file);
	if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
		emit warning(tr("Trying to read from file %1 failed").arg(file)); // todo: remove? It's only in exercise.
		//not really an error, usually
	}

	QStringList result;

	while (!in.atEnd()) {
		const auto line = in.readLine();
		result << QString::fromUtf8(line);
	}

	mInputs = result;
}

void TrikBrick::say(const QString &msg) {
	using namespace kitBase::robotModel;
	using namespace trik::robotModel;
	parts::TrikShell* sh = RobotModelUtils::findDevice<parts::TrikShell>(*mTwoDRobotModel, "ShellPort");
	if (sh == nullptr) {
		qDebug("Error: 2d model shell part was not found");
		return;
	}
	QMetaObject::invokeMethod(sh, "say", Q_ARG(const QString &, msg));
}

void TrikBrick::stop() {
	/// @todo: properly implement this?
	mTwoDRobotModel->stopRobot();
//	for (const auto &m : mMotors) {
//		m->powerOff();
//	}
//	for (const auto &e : mEncoders) {
//		e->reset();
//	}
}

trikControl::MotorInterface *TrikBrick::motor(const QString &port)
{
	using namespace kitBase::robotModel;
	if (!mMotors.contains(port)) {
		robotParts::Motor * mot =
				RobotModelUtils::findDevice<robotParts::Motor>(*mTwoDRobotModel, port);
		if (mot == nullptr) {
			emit error(tr("No configured motor on port: %1").arg(port));
			return nullptr;
		}
		mMotors[port] = new TrikMotorEmu(mot);
	}
	return mMotors[port];
}

trikControl::MarkerInterface *TrikBrick::marker()
{
	kitBase::robotModel::PortInfo markerPort = kitBase::robotModel::RobotModelUtils::findPort(*mTwoDRobotModel
			, "MarkerPort"
			, kitBase::robotModel::Direction::output);
	if (markerPort.isValid()) {
		using Marker = twoDModel::robotModel::parts::Marker;
		Marker* marker = kitBase::robotModel::RobotModelUtils::findDevice<Marker>(*mTwoDRobotModel, markerPort);
		mTrikProxyMarker.reset(new TrikProxyMarker(marker));
		return mTrikProxyMarker.data();
	}

	return nullptr;
}

trikControl::SensorInterface *TrikBrick::sensor(const QString &port)
{
	//testing
	using namespace kitBase::robotModel;
	if (!mSensors.contains(port)) {
		robotParts::ScalarSensor * sens =
				RobotModelUtils::findDevice<robotParts::ScalarSensor>(*mTwoDRobotModel, port);
		if (sens == nullptr) {
			emit error(tr("No configured sensor on port: %1").arg(port));
			return nullptr;
		}
		mSensors[port] = new TrikSensorEmu(sens);
	}
	return mSensors[port];
}

QStringList TrikBrick::motorPorts(trikControl::MotorInterface::Type type) const
{
	Q_UNUSED(type)
//	QLOG_INFO() << "Motor type is ignored";
	return mMotors.keys();
}

QStringList TrikBrick::sensorPorts(trikControl::SensorInterface::Type type) const
{
	Q_UNUSED(type)
//	QLOG_INFO() << "Sensor type is ignored";
	return mMotors.keys();
}

QStringList TrikBrick::encoderPorts() const {
	return mEncoders.keys();
}

trikControl::VectorSensorInterface *TrikBrick::accelerometer() {
	using namespace kitBase::robotModel;
	if (mAccelerometer.isNull()) {
		auto a = RobotModelUtils::findDevice<robotParts::AccelerometerSensor>(*mTwoDRobotModel
				, "AccelerometerPort");
		if (a == nullptr) {
			emit error(tr("No configured accelerometer"));
			return nullptr;
		}
		mAccelerometer.reset(new TrikAccelerometerAdapter(a));
	}

	return mAccelerometer.data();
}

trikControl::GyroSensorInterface *TrikBrick::gyroscope() {
	using namespace kitBase::robotModel;
	if (mGyroscope.isNull()) {
		auto a = RobotModelUtils::findDevice<robotParts::GyroscopeSensor>(*mTwoDRobotModel
				, "GyroscopePort");
		if (a == nullptr) {
			emit error(tr("No configured gyroscope"));
			return nullptr;
		}
		mGyroscope.reset(new TrikGyroscopeAdapter(a, mTwoDRobotModel));
	}

	return mGyroscope.data();
}

trikControl::LineSensorInterface *TrikBrick::lineSensor(const QString &port) {
	using namespace trik::robotModel::parts;
	using namespace kitBase::robotModel;
	if (port == "video0") {
		return lineSensor("LineSensorPort"); // seems to be the case for 2d model
	}

	if (!mLineSensors.contains(port)) {
		TrikLineSensor * sens =
				RobotModelUtils::findDevice<TrikLineSensor>(*mTwoDRobotModel, port);
		if (sens == nullptr) {
			emit error(tr("No configured LineSensor on port: %1").arg(port));
			return nullptr;
		}
		mLineSensors[port] = new TrikLineSensorAdapter(sens);
	}

	return mLineSensors[port];
}

trikControl::EncoderInterface *TrikBrick::encoder(const QString &port) {
	using namespace kitBase::robotModel;
	if (!mEncoders.contains(port)) {
		robotParts::EncoderSensor * enc =
				RobotModelUtils::findDevice<robotParts::EncoderSensor>(*mTwoDRobotModel, port);
		if (enc == nullptr) {
			emit error(tr("No configured encoder on port: %1").arg(port));
			return nullptr;
		}

		mEncoders[port] = new TrikEncoderAdapter(enc->port(), mTwoDRobotModel->engine());
	}

	return mEncoders[port];
}

trikControl::DisplayInterface *TrikBrick::display()
{
//	trik::robotModel::parts::TrikDisplay * const display =
//			kitBase::robotModel::RobotModelUtils::findDevice<trik::robotModel::parts::TrikDisplay>(*mTwoDRobotModel
//					, "DisplayPort");
//	if (display) {
//		bool res = QMetaObject::invokeMethod(display,
//		"drawSmile",
//		Qt::QueuedConnection, // connection type, auto?
//		Q_ARG(bool, false));
//		//display->drawSmile(false);
//		printf(res ? "true" : "false");
//	}
//	return nullptr;
	return &mDisplay;
}

trikControl::LedInterface *TrikBrick::led() {
	using namespace trik::robotModel::parts;
	using namespace kitBase::robotModel;
	if (mLed.isNull()) {
		auto l = RobotModelUtils::findDevice<TrikLed>(*mTwoDRobotModel, "LedPort");
		if (l == nullptr) {
			emit error(tr("No configured led"));
			return nullptr;
		}
		mLed.reset(new TrikLedAdapter(l));
	}

	return mLed.data();
}

int TrikBrick::random(int from, int to)
{
	using namespace kitBase::robotModel;
	auto r = RobotModelUtils::findDevice<robotParts::Random>(*mTwoDRobotModel, "RandomPort");
	// maybe store it later, like the others
	if (!r) {
		emit error(tr("No cofigured random device"));
		return -1;
	}

	return r->random(from, to);
}

void TrikBrick::wait(int milliseconds)
{
	auto timeline = dynamic_cast<twoDModel::model::Timeline *> (&mTwoDRobotModel->timeline());

	if (timeline->isStarted()) {
		QSharedPointer<utils::AbstractTimer> t(timeline->produceTimer());
		QTimer abortTimer;
		QMetaObject::Connection abortConnection;
		QSharedPointer<QEventLoop> loop (new QEventLoop());

		auto mainHandler = [=]() {
			disconnect(abortConnection);
			disconnect(this, &TrikBrick::stopWaiting, nullptr, nullptr);
			disconnect(timeline, &twoDModel::model::Timeline::beforeStop, nullptr, nullptr);
			disconnect(t.data(), &utils::AbstractTimer::timeout, nullptr, nullptr);
			loop->quit();
		};

		auto abortHandler = [=]() {
			if (!timeline->isStarted()) {
				mainHandler();
			}
		};

		connect(t.data(), &utils::AbstractTimer::timeout, mainHandler);
		connect(this, &TrikBrick::stopWaiting, mainHandler);

		// timers that are produced by produceTimer() doesn't use stop singal
		// be careful, one who use just utils::AbstractTimer can stuck
		connect(timeline, &twoDModel::model::Timeline::beforeStop, this, mainHandler);
		abortConnection = connect(&abortTimer, &QTimer::timeout, this, abortHandler);

		// because timer is depends on twoDModel::model::Timeline
		if (timeline->isStarted()) {
			t->start(milliseconds);
			abortTimer.start(10);
			loop->exec();
		} else {
			mainHandler();
		}
	}
}

quint64 TrikBrick::time() const
{
	return mTwoDRobotModel->timeline().timestamp();
}

QStringList TrikBrick::readAll(const QString &path)
{
	if (mIsExcerciseMode) {
		return mInputs;
	}
	//if (mCurrentDir) todo: check that the current working dir is a save dir
	QFileInfo normalizedPath(mCurrentDir.absoluteFilePath(path)); // absoluteDir?
	QString file = normalizedPath.filePath();
	QFile in(file);
	if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
		emit error(tr("Trying to read from file %1 failed").arg(file));
		return {};
	}

	QStringList result;

	while (!in.atEnd()) {
		const auto line = in.readLine();
		result << QString::fromUtf8(line);
	}

	return result;
}

utils::AbstractTimer *TrikBrick::timer(int milliseconds)
{
	utils::AbstractTimer *result = mTwoDRobotModel->timeline().produceTimer();
	mTimers.append(result);
	result->setRepeatable(true); // seems to be the case
	result->start(milliseconds);
	return result;
}

<|endoftext|>


<commit_before>//(c) 2016 by Authors
//This file is a part of ABruijn program.
//Released under the BSD license (see LICENSE file)

#include <stdexcept>
#include <iostream>
#include <unordered_set>
#include <algorithm>
#include <queue>

#include "vertex_index.h"
#include "../common/logger.h"
#include "../common/parallel.h"
#include "../common/config.h"

void VertexIndex::countKmers(size_t hardThreshold, int genomeSize)
{
	if (Parameters::get().kmerSize > 31)
	{
		throw std::runtime_error("Maximum kmer size is 31");
	}

	Logger::get().debug() << "Hard threshold set to " << hardThreshold;
	if (hardThreshold == 0)
	{
		throw std::runtime_error("Wrong hard threshold value: " +
								 std::to_string(hardThreshold));
	}
	Logger::get().debug() << "Started kmer counting";

	size_t preCountSize = 1024 * 1024 * 1024;	//1G by default
	if (genomeSize > (int)Config::get("big_genome_threshold"))
	{
		preCountSize *= 4 * 4;					//16G in case of larger genomes
	}
	auto preCounters = new std::atomic<unsigned char>[preCountSize];
	for (size_t i = 0; i < preCountSize; ++i) preCounters[i] = 0;

	std::vector<FastaRecord::Id> allReads;
	for (auto& hashPair : _seqContainer.getIndex())
	{
		allReads.push_back(hashPair.first);
	}

	//first pass: filling up naive hash counting filter
	if (_outputProgress) Logger::get().info() << "Counting kmers (1/2):";
	std::function<void(const FastaRecord::Id&)> preCountUpdate =
	[&preCounters, hardThreshold, this, preCountSize]
		(const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		int32_t nextKmerPos = _sampleRate;
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}

			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
			}
			size_t kmerBucket = kmerPos.kmer.hash() % preCountSize;

			unsigned char expected = 0;
			while (true)
			{
				expected = preCounters[kmerBucket];
				if (expected == std::numeric_limits<unsigned char>::max())
				{
					break;
				}
				if (preCounters[kmerBucket]
						.compare_exchange_weak(expected, expected + 1))
				{
					break;
				}
			}
		}
	};
	processInParallel(allReads, preCountUpdate,
					  Parameters::get().numThreads, _outputProgress);

	//second pass: counting kmers that have passed the filter
	if (_outputProgress) Logger::get().info() << "Counting kmers (2/2):";

	std::function<void(const FastaRecord::Id&)> countUpdate =
	[&preCounters, hardThreshold, this, preCountSize]
		(const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		int32_t nextKmerPos = _sampleRate;
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}

			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
			}

			size_t count = preCounters[kmerPos.kmer.hash() % preCountSize];
			if (count >= hardThreshold)
			{
				_kmerCounts.upsert(kmerPos.kmer, [](size_t& num){++num;}, 1);
			}
		}
	};
	processInParallel(allReads, countUpdate,
					  Parameters::get().numThreads, _outputProgress);

	for (auto kmer : _kmerCounts.lock_table())
	{
		_kmerDistribution[kmer.second] += 1;
	}
	delete[] preCounters;
}

namespace
{
	struct KmerFreq
	{
		Kmer kmer;
		size_t position;
		size_t freq;
	};
}

void VertexIndex::buildIndexUnevenCoverage(int minCoverage, int maxCoverage)
{
	static const float SELECT_RATE = 0.20;

	if (_outputProgress) Logger::get().info() << "Filling index table";

	_kmerIndex.reserve(10000000);
	std::function<void(const FastaRecord::Id&)> indexUpdate =
	[this, minCoverage, maxCoverage] (const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		//int32_t nextKmerPos = _sampleRate;
		auto cmp = [](const KmerFreq& k1, const KmerFreq& k2)
							{return k1.freq > k2.freq;};
		std::priority_queue<KmerFreq, std::vector<KmerFreq>,
							decltype(cmp)> topKmers(cmp);
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			/*if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}*/
			if (_kmerCounts.contains(kmerPos.kmer))
			{
				topKmers.push({kmerPos.kmer, (size_t)kmerPos.position,
							   _kmerCounts[kmerPos.kmer]});
				if ((int)topKmers.size() >
					SELECT_RATE * _seqContainer.seqLen(readId)) topKmers.pop();
			}
		}

		while (!topKmers.empty())
		{
			KmerPosition kmerPos(topKmers.top().kmer, topKmers.top().position);
			topKmers.pop();

			size_t freq = _kmerCounts.find(kmerPos.kmer);
			if (freq < minCoverage || freq > maxCoverage) continue;

			FastaRecord::Id targetRead = readId;
			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
				targetRead = targetRead.rc();
			}

			_kmerIndex.upsert(kmerPos.kmer,
				[targetRead, &kmerPos](ReadVector& rv)
				{
					if (rv.size == rv.capacity)
					{
						ReadPosition* newBuffer = new ReadPosition[10 + rv.capacity * 2];
						for (size_t i = 0; i < rv.size; ++i) newBuffer[i] = rv.data[i];
						if (rv.data) delete rv.data;
						rv.data = newBuffer;
						rv.capacity = 10 + rv.capacity * 2;
					}
					rv.data[rv.size] = ReadPosition(targetRead,
													kmerPos.position);
					++rv.size;
				}, ReadVector());
		}
	};
	std::vector<FastaRecord::Id> allReads;
	for (auto& hashPair : _seqContainer.getIndex())
	{
		allReads.push_back(hashPair.first);
	}
	processInParallel(allReads, indexUpdate,
					  Parameters::get().numThreads, _outputProgress);

	size_t totalEntries = 0;
	for (auto kmerRec : _kmerIndex.lock_table())
	{
		totalEntries += kmerRec.second.size;
	}
	Logger::get().debug() << "Selected kmers: " << _kmerIndex.size();
	Logger::get().debug() << "Index size: " << totalEntries;

}

void VertexIndex::buildIndex(int minCoverage, int maxCoverage)
{
	if (_outputProgress) Logger::get().info() << "Filling index table";

	//"Replacing" k-mer couns with k-mer index. We need multiple passes
	//to avoid peaks in memory usage during the has table extensions +
	//prevent memory fragmentation

	size_t kmerEntries = 0;
	size_t solidKmers = 0;
	for (auto& kmer : _kmerCounts.lock_table())
	{
		if ((size_t)minCoverage / _sampleRate <= kmer.second &&
			kmer.second <= (size_t)maxCoverage / _sampleRate)
		{
			kmerEntries += kmer.second;
			++solidKmers;
		}
	}
	Logger::get().debug() << "Solid kmers: " << solidKmers;
	Logger::get().debug() << "Kmer index size: " << kmerEntries;

	_kmerIndex.reserve(solidKmers);
	for (auto& kmer : _kmerCounts.lock_table())
	{
		if ((size_t)minCoverage / _sampleRate <= kmer.second &&
			kmer.second <= (size_t)maxCoverage / _sampleRate)
		{
			ReadVector rv((uint32_t)kmer.second, 0);
			_kmerIndex.insert(kmer.first, rv);
		}
	}
	_kmerCounts.clear();
	_kmerCounts.reserve(0);

	_memoryChunks.push_back(new ReadPosition[INDEX_CHUNK]);
	size_t chunkOffset = 0;
	size_t wasted = 0;
	for (auto& kmer : _kmerIndex.lock_table())
	{
		if (INDEX_CHUNK - chunkOffset < kmer.second.capacity)
		{
			wasted += INDEX_CHUNK - chunkOffset;
			_memoryChunks.push_back(new ReadPosition[INDEX_CHUNK]);
			chunkOffset = 0;
		}
		kmer.second.data = _memoryChunks.back() + chunkOffset;
		chunkOffset += kmer.second.capacity;
	}
	//Logger::get().debug() << "Total chunks " << _memoryChunks.size()
	//	<< " wasted space: " << wasted;

	std::function<void(const FastaRecord::Id&)> indexUpdate =
	[this] (const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		int32_t nextKmerPos = _sampleRate;
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}

			FastaRecord::Id targetRead = readId;
			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
				targetRead = targetRead.rc();
			}

			_kmerIndex.update_fn(kmerPos.kmer,
				[targetRead, &kmerPos](ReadVector& rv)
				{

					rv.data[rv.size] = ReadPosition(targetRead,
													kmerPos.position);
					++rv.size;
				});
		}
	};
	std::vector<FastaRecord::Id> allReads;
	for (auto& hashPair : _seqContainer.getIndex())
	{
		allReads.push_back(hashPair.first);
	}
	processInParallel(allReads, indexUpdate,
					  Parameters::get().numThreads, _outputProgress);
}

void VertexIndex::clear()
{
	for (auto& chunk : _memoryChunks) delete[] chunk;
	_memoryChunks.clear();

	_kmerIndex.clear();
	_kmerIndex.reserve(0);

	_kmerCounts.clear();
	_kmerCounts.reserve(0);
}
<commit_msg>minor change<commit_after>//(c) 2016 by Authors
//This file is a part of ABruijn program.
//Released under the BSD license (see LICENSE file)

#include <stdexcept>
#include <iostream>
#include <unordered_set>
#include <algorithm>
#include <queue>

#include "vertex_index.h"
#include "../common/logger.h"
#include "../common/parallel.h"
#include "../common/config.h"

void VertexIndex::countKmers(size_t hardThreshold, int genomeSize)
{
	if (Parameters::get().kmerSize > 31)
	{
		throw std::runtime_error("Maximum kmer size is 31");
	}

	Logger::get().debug() << "Hard threshold set to " << hardThreshold;
	if (hardThreshold == 0)
	{
		throw std::runtime_error("Wrong hard threshold value: " +
								 std::to_string(hardThreshold));
	}
	Logger::get().debug() << "Started kmer counting";

	size_t preCountSize = 1024 * 1024 * 1024;	//1G by default
	if (genomeSize > (int)Config::get("big_genome_threshold"))
	{
		preCountSize *= 4 * 4;					//16G in case of larger genomes
	}
	auto preCounters = new std::atomic<unsigned char>[preCountSize];
	for (size_t i = 0; i < preCountSize; ++i) preCounters[i] = 0;

	std::vector<FastaRecord::Id> allReads;
	for (auto& hashPair : _seqContainer.getIndex())
	{
		allReads.push_back(hashPair.first);
	}

	//first pass: filling up naive hash counting filter
	if (_outputProgress) Logger::get().info() << "Counting kmers (1/2):";
	std::function<void(const FastaRecord::Id&)> preCountUpdate =
	[&preCounters, hardThreshold, this, preCountSize]
		(const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		int32_t nextKmerPos = _sampleRate;
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}

			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
			}
			size_t kmerBucket = kmerPos.kmer.hash() % preCountSize;

			unsigned char expected = 0;
			while (true)
			{
				expected = preCounters[kmerBucket];
				if (expected == std::numeric_limits<unsigned char>::max())
				{
					break;
				}
				if (preCounters[kmerBucket]
						.compare_exchange_weak(expected, expected + 1))
				{
					break;
				}
			}
		}
	};
	processInParallel(allReads, preCountUpdate,
					  Parameters::get().numThreads, _outputProgress);

	//second pass: counting kmers that have passed the filter
	if (_outputProgress) Logger::get().info() << "Counting kmers (2/2):";

	std::function<void(const FastaRecord::Id&)> countUpdate =
	[&preCounters, hardThreshold, this, preCountSize]
		(const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		int32_t nextKmerPos = _sampleRate;
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}

			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
			}

			size_t count = preCounters[kmerPos.kmer.hash() % preCountSize];
			if (count >= hardThreshold)
			{
				_kmerCounts.upsert(kmerPos.kmer, [](size_t& num){++num;}, 1);
			}
		}
	};
	processInParallel(allReads, countUpdate,
					  Parameters::get().numThreads, _outputProgress);

	for (auto kmer : _kmerCounts.lock_table())
	{
		_kmerDistribution[kmer.second] += 1;
	}
	delete[] preCounters;
}

namespace
{
	struct KmerFreq
	{
		Kmer kmer;
		size_t position;
		size_t freq;
	};
}

void VertexIndex::buildIndexUnevenCoverage(int minCoverage, int maxCoverage)
{
	static const float SELECT_RATE = 0.20;

	if (_outputProgress) Logger::get().info() << "Filling index table";

	_kmerIndex.reserve(10000000);
	std::function<void(const FastaRecord::Id&)> indexUpdate =
	[this, minCoverage, maxCoverage] (const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		//int32_t nextKmerPos = _sampleRate;
		auto cmp = [](const KmerFreq& k1, const KmerFreq& k2)
							{return k1.freq > k2.freq;};
		std::priority_queue<KmerFreq, std::vector<KmerFreq>,
							decltype(cmp)> topKmers(cmp);
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			/*if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}*/
			if (_kmerCounts.contains(kmerPos.kmer))
			{
				topKmers.push({kmerPos.kmer, (size_t)kmerPos.position,
							   _kmerCounts[kmerPos.kmer]});
				if ((int)topKmers.size() >
					SELECT_RATE * _seqContainer.seqLen(readId)) topKmers.pop();
			}
		}

		while (!topKmers.empty())
		{
			KmerPosition kmerPos(topKmers.top().kmer, topKmers.top().position);
			topKmers.pop();

			int freq = _kmerCounts.find(kmerPos.kmer);
			if (freq < minCoverage || freq > maxCoverage) continue;

			FastaRecord::Id targetRead = readId;
			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
				targetRead = targetRead.rc();
			}

			_kmerIndex.upsert(kmerPos.kmer,
				[targetRead, &kmerPos](ReadVector& rv)
				{
					if (rv.size == rv.capacity)
					{
						ReadPosition* newBuffer = new ReadPosition[10 + rv.capacity * 2];
						for (size_t i = 0; i < rv.size; ++i) newBuffer[i] = rv.data[i];
						if (rv.data) delete rv.data;
						rv.data = newBuffer;
						rv.capacity = 10 + rv.capacity * 2;
					}
					rv.data[rv.size] = ReadPosition(targetRead,
													kmerPos.position);
					++rv.size;
				}, ReadVector());
		}
	};
	std::vector<FastaRecord::Id> allReads;
	for (auto& hashPair : _seqContainer.getIndex())
	{
		allReads.push_back(hashPair.first);
	}
	processInParallel(allReads, indexUpdate,
					  Parameters::get().numThreads, _outputProgress);

	size_t totalEntries = 0;
	for (auto kmerRec : _kmerIndex.lock_table())
	{
		totalEntries += kmerRec.second.size;
	}
	Logger::get().debug() << "Selected kmers: " << _kmerIndex.size();
	Logger::get().debug() << "Index size: " << totalEntries;

}

void VertexIndex::buildIndex(int minCoverage, int maxCoverage)
{
	if (_outputProgress) Logger::get().info() << "Filling index table";

	//"Replacing" k-mer couns with k-mer index. We need multiple passes
	//to avoid peaks in memory usage during the has table extensions +
	//prevent memory fragmentation

	size_t kmerEntries = 0;
	size_t solidKmers = 0;
	for (auto& kmer : _kmerCounts.lock_table())
	{
		if ((size_t)minCoverage / _sampleRate <= kmer.second &&
			kmer.second <= (size_t)maxCoverage / _sampleRate)
		{
			kmerEntries += kmer.second;
			++solidKmers;
		}
	}
	Logger::get().debug() << "Solid kmers: " << solidKmers;
	Logger::get().debug() << "Kmer index size: " << kmerEntries;

	_kmerIndex.reserve(solidKmers);
	for (auto& kmer : _kmerCounts.lock_table())
	{
		if ((size_t)minCoverage / _sampleRate <= kmer.second &&
			kmer.second <= (size_t)maxCoverage / _sampleRate)
		{
			ReadVector rv((uint32_t)kmer.second, 0);
			_kmerIndex.insert(kmer.first, rv);
		}
	}
	_kmerCounts.clear();
	_kmerCounts.reserve(0);

	_memoryChunks.push_back(new ReadPosition[INDEX_CHUNK]);
	size_t chunkOffset = 0;
	size_t wasted = 0;
	for (auto& kmer : _kmerIndex.lock_table())
	{
		if (INDEX_CHUNK - chunkOffset < kmer.second.capacity)
		{
			wasted += INDEX_CHUNK - chunkOffset;
			_memoryChunks.push_back(new ReadPosition[INDEX_CHUNK]);
			chunkOffset = 0;
		}
		kmer.second.data = _memoryChunks.back() + chunkOffset;
		chunkOffset += kmer.second.capacity;
	}
	//Logger::get().debug() << "Total chunks " << _memoryChunks.size()
	//	<< " wasted space: " << wasted;

	std::function<void(const FastaRecord::Id&)> indexUpdate =
	[this] (const FastaRecord::Id& readId)
	{
		if (!readId.strand()) return;

		int32_t nextKmerPos = _sampleRate;
		for (auto kmerPos : IterKmers(_seqContainer.getSeq(readId)))
		{
			if (_sampleRate > 1) //subsampling
			{
				if (--nextKmerPos > 0) continue;
				nextKmerPos = _sampleRate + (int32_t)(kmerPos.kmer.hash() % 3) - 1;
			}

			FastaRecord::Id targetRead = readId;
			bool revCmp = kmerPos.kmer.standardForm();
			if (revCmp)
			{
				kmerPos.position = _seqContainer.seqLen(readId) -
										kmerPos.position -
										Parameters::get().kmerSize;
				targetRead = targetRead.rc();
			}

			_kmerIndex.update_fn(kmerPos.kmer,
				[targetRead, &kmerPos](ReadVector& rv)
				{

					rv.data[rv.size] = ReadPosition(targetRead,
													kmerPos.position);
					++rv.size;
				});
		}
	};
	std::vector<FastaRecord::Id> allReads;
	for (auto& hashPair : _seqContainer.getIndex())
	{
		allReads.push_back(hashPair.first);
	}
	processInParallel(allReads, indexUpdate,
					  Parameters::get().numThreads, _outputProgress);
}

void VertexIndex::clear()
{
	for (auto& chunk : _memoryChunks) delete[] chunk;
	_memoryChunks.clear();

	_kmerIndex.clear();
	_kmerIndex.reserve(0);

	_kmerCounts.clear();
	_kmerCounts.reserve(0);
}
<|endoftext|>


<commit_before>
/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
   ATS

   License: see $ATS_DIR/COPYRIGHT
   Author: Markus Berndt

   Interface for the Prescribed Deformation PK.

   <ParameterList name="prescribed deformation">
      <Parameter name="PK model" type="string" value="Prescibed Mesh Deformation"/>
      <Parameter name="Deformation method" type="string" value="method name"/>
   </ParameterList>

   ------------------------------------------------------------------------- */

#include "prescribed_deformation.hh"
#include "porosity_evaluator.hh"

namespace Amanzi {
namespace Deform {

using namespace Amanzi::AmanziMesh;

RegisteredPKFactory<PrescribedDeformation> PrescribedDeformation::reg_("prescribed deformation");

PrescribedDeformation::PrescribedDeformation(Teuchos::ParameterList& plist,
                                             const Teuchos::RCP<TreeVector>& solution):
    PKDefaultBase(plist,solution),
    PKPhysicalBase(plist,solution)
{

}

// -- Setup data
void PrescribedDeformation::setup(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::setup(S);

  std::vector<AmanziMesh::Entity_kind> location(1);
  location[0] = AmanziMesh::CELL;
  std::vector<int> num_dofs(1);
  num_dofs[0] = 1;
  std::vector<std::string> name(1);
  name[0] = "cell";

  S->RequireField(key_, name_)->SetMesh(mesh_)->SetGhosted()
    ->SetComponents(name, location, num_dofs);

  std::cout << key_ << endl;
  std::cout << name_ << endl;

}

// -- Initialize owned (dependent) variables.
void PrescribedDeformation::initialize(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::initialize(S);

}

// -- advance via one of a few methods
bool PrescribedDeformation::advance(double dt) {
  std::cout << "ADVANCING prescribed deformation" << std:: endl;

  AmanziMesh::Mesh * write_access_mesh_ =  const_cast<AmanziMesh::Mesh*>(&*S_next_->GetMesh());

  Teuchos::RCP<CompositeVector> cell_volume = S_next_->GetFieldData("cell_volume", "cell_volume");
  // Teuchos::RCP<FieldEvaluator> cveval = S_next_->GetFieldEvaluator("cell_volume");

  double ss = S_next_->time();
  double ss0 = S_->time();

  double thickness = 0.8 + 0.2*cos( ss / (365.25*24*60*60) * 2.0*M_PI );
  double thickness0 = 0.8 + 0.2*cos( ss0 / (365.25*24*60*60) * 2.0*M_PI );

  double factor = thickness/thickness0;

  std::cout << "factor = " << factor << std::endl;

  // get space dimensions
  int dim = write_access_mesh_->space_dimension();

    // set the list of the new position coords
  AmanziGeometry::Point_List newpos, finpos;

  // move the mid point on the mesh top
  Entity_ID_List nodeids;

  // number of vertices
  int nV = write_access_mesh_->num_entities(Amanzi::AmanziMesh::NODE,
                               Amanzi::AmanziMesh::OWNED);

  std::cout << "number of nodes = " << nV << std::endl;

  Amanzi::AmanziGeometry::Point coords, new_coords;
  coords.init(dim);
  new_coords.init(dim);

  // search the id of the mid point on the top
  for (int iV=0; iV<nV; iV++) {

    // get the coords of the node
    write_access_mesh_->node_get_coordinates(iV,&coords);

    for ( int s=0; s<dim-1; ++s ) {
      new_coords[s] = coords[s];
    }
    // new_coords[dim-1] = coords[dim-1] * fac;
    new_coords[dim-1] = coords[dim-1] * factor;

    // puch back for deform method
    nodeids.push_back(iV);
    newpos.push_back( new_coords );
  }

  std::cout << "now modifying the mesh..." << std::endl;
  // compute the deformed mesh
  write_access_mesh_->deform( nodeids, newpos, true, &finpos);

  std::cout << "cell volume = " << write_access_mesh_->cell_volume(0) << std::endl;

  // now update cell volumes
  cell_volume->Scale(factor);

  solution_evaluator_->SetFieldAsChanged();

  std::cout << "DONE" << std::endl;
}

} // namespace
} // namespace

<commit_msg>intermediate commit<commit_after>
/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
   ATS

   License: see $ATS_DIR/COPYRIGHT
   Author: Markus Berndt

   Interface for the Prescribed Deformation PK.

   <ParameterList name="prescribed deformation">
      <Parameter name="PK model" type="string" value="Prescibed Mesh Deformation"/>
      <Parameter name="Deformation method" type="string" value="method name"/>
   </ParameterList>

   ------------------------------------------------------------------------- */

#include "prescribed_deformation.hh"
#include "porosity_evaluator.hh"

namespace Amanzi {
namespace Deform {

using namespace Amanzi::AmanziMesh;

RegisteredPKFactory<PrescribedDeformation> PrescribedDeformation::reg_("prescribed deformation");

PrescribedDeformation::PrescribedDeformation(Teuchos::ParameterList& plist,
                                             const Teuchos::RCP<TreeVector>& solution):
    PKDefaultBase(plist,solution),
    PKPhysicalBase(plist,solution)
{

}

// -- Setup data
void PrescribedDeformation::setup(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::setup(S);

  std::vector<AmanziMesh::Entity_kind> location(1);
  location[0] = AmanziMesh::CELL;
  std::vector<int> num_dofs(1);
  num_dofs[0] = 1;
  std::vector<std::string> name(1);
  name[0] = "cell";

  S->RequireField(key_, name_)->SetMesh(mesh_)->SetGhosted()
    ->SetComponents(name, location, num_dofs);

  std::cout << key_ << endl;
  std::cout << name_ << endl;

}

// -- Initialize owned (dependent) variables.
void PrescribedDeformation::initialize(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::initialize(S);

}

// -- advance via one of a few methods
bool PrescribedDeformation::advance(double dt) {
  std::cout << "ADVANCING prescribed deformation" << std:: endl;

  AmanziMesh::Mesh * write_access_mesh_ =  const_cast<AmanziMesh::Mesh*>(&*S_next_->GetMesh());

  Teuchos::RCP<CompositeVector> cell_volume = S_next_->GetFieldData("cell_volume", "cell_volume");
  // Teuchos::RCP<FieldEvaluator> cveval = S_next_->GetFieldEvaluator("cell_volume");

  double ss = S_next_->time();
  double ss0 = S_->time();

  double thickness = 0.8 + 0.2*cos( ss / (365.25*24*60*60) * 2.0*M_PI );
  double thickness0 = 0.8 + 0.2*cos( ss0 / (365.25*24*60*60) * 2.0*M_PI );

  double factor = thickness/thickness0;

  std::cout << "factor = " << factor << std::endl;

  // get space dimensions
  int dim = write_access_mesh_->space_dimension();

    // set the list of the new position coords
  AmanziGeometry::Point_List newpos, finpos;

  // move the mid point on the mesh top
  Entity_ID_List nodeids;

  // number of vertices
  int nV = write_access_mesh_->num_entities(Amanzi::AmanziMesh::NODE,
                               Amanzi::AmanziMesh::OWNED);

  std::cout << "number of nodes = " << nV << std::endl;

  Amanzi::AmanziGeometry::Point coords, new_coords;
  coords.init(dim);
  new_coords.init(dim);

  // search the id of the mid point on the top
  for (int iV=0; iV<nV; iV++) {

    // get the coords of the node
    write_access_mesh_->node_get_coordinates(iV,&coords);

    for ( int s=0; s<dim-1; ++s ) {
      new_coords[s] = coords[s];
    }
    // new_coords[dim-1] = coords[dim-1] * fac;
    new_coords[dim-1] = coords[dim-1] * factor;

    // puch back for deform method
    nodeids.push_back(iV);
    newpos.push_back( new_coords );
  }

  const CompositeVector& cv = *S_->GetFieldData("cell_volume"); //->ViewComponent("cell",false);

  solution_->set_data(cv);

  // compute the deformed mesh
  write_access_mesh_->deform( nodeids, newpos, true, &finpos);

  solution_evaluator_->SetFieldAsChanged();

  std::cout << "DONE" << std::endl;
}

} // namespace
} // namespace

<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <inviwo/core/datastructures/bitset.h>
#include <inviwo/core/io/serialization/serializer.h>
#include <inviwo/core/io/serialization/deserializer.h>
#include <inviwo/core/algorithm/base64.h>

#include <warn/push>
#include <warn/ignore/all>
#include <roaring.hh>
#include <warn/pop>

namespace inviwo {

BitSet::BitSetIterator::BitSetIterator(const BitSetIterator& rhs)
    : it_(std::make_unique<RoaringIt>(*rhs.it_)) {}

auto BitSet::BitSetIterator::operator=(const BitSetIterator& rhs) -> BitSetIterator& {
    if (this != &rhs) {
        *it_ = *rhs.it_;
    }
    return *this;
}

BitSet::BitSetIterator::~BitSetIterator() = default;

BitSet::BitSetIterator::BitSetIterator(const BitSet& b, bool exhausted)
    : it_(std::make_unique<RoaringIt>(*b.roaring_, exhausted)) {}

BitSet::BitSetIterator::BitSetIterator(const RoaringIt& it)
    : it_(std::make_unique<RoaringIt>(it)) {}

BitSet::BitSetIterator& BitSet::BitSetIterator::operator++() {
    it_->operator++();
    return *this;
}

BitSet::BitSetIterator BitSet::BitSetIterator::operator++(int) {
    BitSet::BitSetIterator it(*it_);
    it_->operator++();
    return it;
}

BitSet::BitSetIterator& BitSet::BitSetIterator::operator--() {
    it_->operator--();
    return *this;
}

BitSet::BitSetIterator BitSet::BitSetIterator::operator--(int) {
    BitSetIterator it(*it_);
    it_->operator--();
    return it;
}

auto BitSet::BitSetIterator::operator*() const -> value_type { return **it_; }

bool BitSet::BitSetIterator::operator==(const BitSetIterator& rhs) const {
    return it_->operator==(*rhs.it_);
}

bool BitSet::BitSetIterator::operator!=(const BitSetIterator& rhs) const {
    return it_->operator!=(*rhs.it_);
}

BitSet::BitSet() : roaring_(std::make_unique<roaring::Roaring>()) {}

BitSet::BitSet(util::span<const uint32_t> span) : BitSet() { addMany(span.size(), span.data()); }

BitSet::BitSet(const roaring::Roaring& roaring)
    : roaring_(std::make_unique<roaring::Roaring>(roaring)) {}

BitSet::BitSet(roaring::Roaring&& roaring)
    : roaring_(std::make_unique<roaring::Roaring>(std::move(roaring))) {}

BitSet::BitSet(const BitSet& rhs) : roaring_(std::make_unique<roaring::Roaring>(*rhs.roaring_)) {}

BitSet::BitSet(BitSet&& rhs) noexcept : roaring_(std::move(rhs.roaring_)) {}

BitSet::~BitSet() = default;

BitSet& BitSet::operator=(const BitSet& rhs) {
    if (this != &rhs) {
        *roaring_ = *rhs.roaring_;
    }
    return *this;
}

BitSet& BitSet::operator=(BitSet&& rhs) noexcept {
    roaring_ = std::move(rhs.roaring_);
    return *this;
}

auto BitSet::begin() const -> BitSetIterator { return BitSetIterator(*this, false); }

auto BitSet::end() const -> BitSetIterator { return BitSetIterator(*this, true); }

uint32_t BitSet::cardinality() const { return static_cast<uint32_t>(roaring_->cardinality()); }

size_t BitSet::size() const { return static_cast<size_t>(roaring_->cardinality()); }

bool BitSet::empty() const { return roaring_->isEmpty(); }

void BitSet::clear() { roaring::api::roaring_bitmap_clear(&roaring_->roaring); }

bool BitSet::isSubsetOf(const BitSet& b) const { return roaring_->isSubset(*(b.roaring_)); }

bool BitSet::isStrictSubsetOf(const BitSet& b) const {
    return roaring_->isStrictSubset(*(b.roaring_));
}

void BitSet::add(util::span<const uint32_t> span) { addMany(span.size(), span.data()); }

bool BitSet::addChecked(uint32_t v) { return roaring_->addChecked(v); }

void BitSet::addRange(uint32_t min, uint32_t max) { roaring_->addRange(min, max); }

void BitSet::addRangeClosed(uint32_t min, uint32_t max) {
    roaring::api::roaring_bitmap_add_range_closed(&roaring_->roaring, min, max);
}

void BitSet::remove(uint32_t v) { roaring_->remove(v); }

bool BitSet::removeChecked(uint32_t v) { return roaring_->removeChecked(v); }

uint32_t BitSet::max() const { return roaring_->maximum(); }

uint32_t BitSet::min() const { return roaring_->minimum(); }

bool BitSet::contains(uint32_t v) const { return roaring_->contains(v); }

bool BitSet::containsRange(uint32_t min, uint32_t max) const {
    return roaring_->containsRange(min, max);
}

void BitSet::flip(uint32_t v) { roaring_->flip(v, v + 1); }

void BitSet::flipRange(uint32_t min, uint32_t max) { roaring_->flip(min, max); }

size_t BitSet::rank(uint32_t v) const { return roaring_->rank(v); }

bool BitSet::operator==(const BitSet& b) const { return roaring_->operator==(*b.roaring_); }

bool BitSet::operator!=(const BitSet& b) const { return !operator==(b); }

bool BitSet::intersect(const BitSet& b) const { return roaring_->intersect(*(b.roaring_)); }

size_t BitSet::orCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

size_t BitSet::andCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

size_t BitSet::andNotCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

size_t BitSet::xorCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

double BitSet::jaccardIndex(const BitSet& b) const {
    return roaring_->jaccard_index(*(b.roaring_));
}

BitSet& BitSet::operator&=(const BitSet& b) {
    roaring_->operator&=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator&(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator&(*(b.roaring_));
    return result;
}

BitSet& BitSet::operator-=(const BitSet& b) {
    roaring_->operator-=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator-(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator-(*(b.roaring_));
    return result;
}

BitSet& BitSet::operator|=(const BitSet& b) {
    roaring_->operator|=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator|(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator|(*(b.roaring_));
    return result;
}

BitSet& BitSet::operator^=(const BitSet& b) {
    roaring_->operator^=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator^(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator^(*(b.roaring_));
    return result;
}

BitSet BitSet::fastUnion(util::span<const BitSet*> bitsets) {
    using namespace roaring;

    std::vector<const Roaring*> inputs;
    for (auto b : bitsets) {
        inputs.push_back(b->roaring_.get());
    }

    return BitSet(Roaring::fastunion(inputs.size(), inputs.data()));
}

std::vector<uint32_t> BitSet::toVector() const {
    std::vector<uint32_t> v(cardinality());
    roaring_->toUint32Array(v.data());
    return v;
}

std::string BitSet::toString() const { return roaring_->toString(); }

size_t BitSet::getSizeInBytes() const { return roaring_->getSizeInBytes(true); }

void BitSet::writeData(std::ostream& os) const {
    std::vector<char> buf(getSizeInBytes());
    const size_t numBytes = roaring_->write(buf.data(), true);
    os << static_cast<uint32_t>(numBytes);
    os.write(buf.data(), numBytes);
}

void BitSet::readData(std::istream& is) {
    try {
        uint32_t numBytes = 0u;
        is >> numBytes;
        std::vector<char> buf(numBytes);
        is.read(buf.data(), numBytes);
        *roaring_ = roaring::Roaring::read(buf.data(), true);
    } catch (std::runtime_error) {
        throw Exception("Error reading BitSet", IVW_CONTEXT);
    }
}

void BitSet::optimize() { roaring_->runOptimize(); }

void BitSet::removeRLECompression() { roaring_->removeRunCompression(); }

size_t BitSet::shrinkToFit() { return roaring_->shrinkToFit(); }

void BitSet::serialize(Serializer& s) const {
    std::vector<char> buf(getSizeInBytes());
    roaring_->write(buf.data(), true);

    s.serialize("bitset", util::base64_encode(buf));
}

void BitSet::deserialize(Deserializer& d) {
    std::string str;
    d.deserialize("bitset", str);

    str = util::base64_decode(str);
    *roaring_ = roaring::Roaring::read(str.data(), true);
}

void BitSet::addSingle(uint32_t v) { roaring_->add(v); }

void BitSet::addMany(size_t size, const uint32_t* data) { roaring_->addMany(size, data); }

}  // namespace inviwo
<commit_msg>Core: warn fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <inviwo/core/datastructures/bitset.h>
#include <inviwo/core/io/serialization/serializer.h>
#include <inviwo/core/io/serialization/deserializer.h>
#include <inviwo/core/algorithm/base64.h>

#include <warn/push>
#include <warn/ignore/all>
#include <roaring.hh>
#include <warn/pop>

namespace inviwo {

BitSet::BitSetIterator::BitSetIterator(const BitSetIterator& rhs)
    : it_(std::make_unique<RoaringIt>(*rhs.it_)) {}

auto BitSet::BitSetIterator::operator=(const BitSetIterator& rhs) -> BitSetIterator& {
    if (this != &rhs) {
        *it_ = *rhs.it_;
    }
    return *this;
}

BitSet::BitSetIterator::~BitSetIterator() = default;

BitSet::BitSetIterator::BitSetIterator(const BitSet& b, bool exhausted)
    : it_(std::make_unique<RoaringIt>(*b.roaring_, exhausted)) {}

BitSet::BitSetIterator::BitSetIterator(const RoaringIt& it)
    : it_(std::make_unique<RoaringIt>(it)) {}

BitSet::BitSetIterator& BitSet::BitSetIterator::operator++() {
    it_->operator++();
    return *this;
}

BitSet::BitSetIterator BitSet::BitSetIterator::operator++(int) {
    BitSet::BitSetIterator it(*it_);
    it_->operator++();
    return it;
}

BitSet::BitSetIterator& BitSet::BitSetIterator::operator--() {
    it_->operator--();
    return *this;
}

BitSet::BitSetIterator BitSet::BitSetIterator::operator--(int) {
    BitSetIterator it(*it_);
    it_->operator--();
    return it;
}

auto BitSet::BitSetIterator::operator*() const -> value_type { return **it_; }

bool BitSet::BitSetIterator::operator==(const BitSetIterator& rhs) const {
    return it_->operator==(*rhs.it_);
}

bool BitSet::BitSetIterator::operator!=(const BitSetIterator& rhs) const {
    return it_->operator!=(*rhs.it_);
}

BitSet::BitSet() : roaring_(std::make_unique<roaring::Roaring>()) {}

BitSet::BitSet(util::span<const uint32_t> span) : BitSet() { addMany(span.size(), span.data()); }

BitSet::BitSet(const roaring::Roaring& roaring)
    : roaring_(std::make_unique<roaring::Roaring>(roaring)) {}

BitSet::BitSet(roaring::Roaring&& roaring)
    : roaring_(std::make_unique<roaring::Roaring>(std::move(roaring))) {}

BitSet::BitSet(const BitSet& rhs) : roaring_(std::make_unique<roaring::Roaring>(*rhs.roaring_)) {}

BitSet::BitSet(BitSet&& rhs) noexcept : roaring_(std::move(rhs.roaring_)) {}

BitSet::~BitSet() = default;

BitSet& BitSet::operator=(const BitSet& rhs) {
    if (this != &rhs) {
        *roaring_ = *rhs.roaring_;
    }
    return *this;
}

BitSet& BitSet::operator=(BitSet&& rhs) noexcept {
    roaring_ = std::move(rhs.roaring_);
    return *this;
}

auto BitSet::begin() const -> BitSetIterator { return BitSetIterator(*this, false); }

auto BitSet::end() const -> BitSetIterator { return BitSetIterator(*this, true); }

uint32_t BitSet::cardinality() const { return static_cast<uint32_t>(roaring_->cardinality()); }

size_t BitSet::size() const { return static_cast<size_t>(roaring_->cardinality()); }

bool BitSet::empty() const { return roaring_->isEmpty(); }

void BitSet::clear() { roaring::api::roaring_bitmap_clear(&roaring_->roaring); }

bool BitSet::isSubsetOf(const BitSet& b) const { return roaring_->isSubset(*(b.roaring_)); }

bool BitSet::isStrictSubsetOf(const BitSet& b) const {
    return roaring_->isStrictSubset(*(b.roaring_));
}

void BitSet::add(util::span<const uint32_t> span) { addMany(span.size(), span.data()); }

bool BitSet::addChecked(uint32_t v) { return roaring_->addChecked(v); }

void BitSet::addRange(uint32_t min, uint32_t max) { roaring_->addRange(min, max); }

void BitSet::addRangeClosed(uint32_t min, uint32_t max) {
    roaring::api::roaring_bitmap_add_range_closed(&roaring_->roaring, min, max);
}

void BitSet::remove(uint32_t v) { roaring_->remove(v); }

bool BitSet::removeChecked(uint32_t v) { return roaring_->removeChecked(v); }

uint32_t BitSet::max() const { return roaring_->maximum(); }

uint32_t BitSet::min() const { return roaring_->minimum(); }

bool BitSet::contains(uint32_t v) const { return roaring_->contains(v); }

bool BitSet::containsRange(uint32_t min, uint32_t max) const {
    return roaring_->containsRange(min, max);
}

void BitSet::flip(uint32_t v) { roaring_->flip(v, v + 1); }

void BitSet::flipRange(uint32_t min, uint32_t max) { roaring_->flip(min, max); }

size_t BitSet::rank(uint32_t v) const { return roaring_->rank(v); }

bool BitSet::operator==(const BitSet& b) const { return roaring_->operator==(*b.roaring_); }

bool BitSet::operator!=(const BitSet& b) const { return !operator==(b); }

bool BitSet::intersect(const BitSet& b) const { return roaring_->intersect(*(b.roaring_)); }

size_t BitSet::orCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

size_t BitSet::andCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

size_t BitSet::andNotCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

size_t BitSet::xorCardinality(const BitSet& b) const {
    return roaring_->and_cardinality(*(b.roaring_));
}

double BitSet::jaccardIndex(const BitSet& b) const {
    return roaring_->jaccard_index(*(b.roaring_));
}

BitSet& BitSet::operator&=(const BitSet& b) {
    roaring_->operator&=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator&(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator&(*(b.roaring_));
    return result;
}

BitSet& BitSet::operator-=(const BitSet& b) {
    roaring_->operator-=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator-(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator-(*(b.roaring_));
    return result;
}

BitSet& BitSet::operator|=(const BitSet& b) {
    roaring_->operator|=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator|(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator|(*(b.roaring_));
    return result;
}

BitSet& BitSet::operator^=(const BitSet& b) {
    roaring_->operator^=(*(b.roaring_));
    return *this;
}

BitSet BitSet::operator^(const BitSet& b) const {
    BitSet result;
    *result.roaring_ = roaring_->operator^(*(b.roaring_));
    return result;
}

BitSet BitSet::fastUnion(util::span<const BitSet*> bitsets) {
    using namespace roaring;

    std::vector<const Roaring*> inputs;
    for (auto b : bitsets) {
        inputs.push_back(b->roaring_.get());
    }

    return BitSet(Roaring::fastunion(inputs.size(), inputs.data()));
}

std::vector<uint32_t> BitSet::toVector() const {
    std::vector<uint32_t> v(cardinality());
    roaring_->toUint32Array(v.data());
    return v;
}

std::string BitSet::toString() const { return roaring_->toString(); }

size_t BitSet::getSizeInBytes() const { return roaring_->getSizeInBytes(true); }

void BitSet::writeData(std::ostream& os) const {
    std::vector<char> buf(getSizeInBytes());
    const size_t numBytes = roaring_->write(buf.data(), true);
    os << static_cast<uint32_t>(numBytes);
    os.write(buf.data(), numBytes);
}

void BitSet::readData(std::istream& is) {
    try {
        uint32_t numBytes = 0u;
        is >> numBytes;
        std::vector<char> buf(numBytes);
        is.read(buf.data(), numBytes);
        *roaring_ = roaring::Roaring::read(buf.data(), true);
    } catch (std::runtime_error&) {
        throw Exception("Error reading BitSet", IVW_CONTEXT);
    }
}

void BitSet::optimize() { roaring_->runOptimize(); }

void BitSet::removeRLECompression() { roaring_->removeRunCompression(); }

size_t BitSet::shrinkToFit() { return roaring_->shrinkToFit(); }

void BitSet::serialize(Serializer& s) const {
    std::vector<char> buf(getSizeInBytes());
    roaring_->write(buf.data(), true);

    s.serialize("bitset", util::base64_encode(buf));
}

void BitSet::deserialize(Deserializer& d) {
    std::string str;
    d.deserialize("bitset", str);

    str = util::base64_decode(str);
    *roaring_ = roaring::Roaring::read(str.data(), true);
}

void BitSet::addSingle(uint32_t v) { roaring_->add(v); }

void BitSet::addMany(size_t size, const uint32_t* data) { roaring_->addMany(size, data); }

}  // namespace inviwo
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you 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.

*******************************************************************************/

//==============================================================================
// Standard file manager
//==============================================================================

#include "corecliutils.h"
#include "filemanager.h"
#include "standardfilemanager.h"
#include "standardsupportplugin.h"

//==============================================================================

namespace OpenCOR {
namespace StandardSupport {

//==============================================================================

StandardFileManager::StandardFileManager() :
    mFiles(Files())
{
    // Create some connections to keep track of some events related to our
    // 'global' file manager

    Core::FileManager *fileManagerInstance = Core::FileManager::instance();

    connect(fileManagerInstance, SIGNAL(fileManaged(const QString &)),
            this, SLOT(manageFile(const QString &)));
    connect(fileManagerInstance, SIGNAL(fileUnmanaged(const QString &)),
            this, SLOT(unmanageFile(const QString &)));

    connect(fileManagerInstance, SIGNAL(fileReloaded(const QString &)),
            this, SLOT(reloadFile(const QString &)));

    connect(fileManagerInstance, SIGNAL(fileRenamed(const QString &, const QString &)),
            this, SLOT(renameFile(const QString &, const QString &)));
}

//==============================================================================

StandardFileManager::~StandardFileManager()
{
    // Remove all the managed files

    foreach (QObject *file, mFiles)
        delete file;
}

//==============================================================================

bool StandardFileManager::isFile(const QString &pFileName)
{
    // If the given file is already managed, then we consider that it's of the
    // right type (e.g. CellML file), even though it may not be of the right
    // anymore after having been edited and saved, but in this case it's good to
    // keep considering the file as of the right type, so that the user can
    // continue editing it without any problem, for example

    QString nativeFileName = Core::nativeCanonicalFileName(pFileName);

    if (file(nativeFileName))
        return true;

    // The given file is not managed, so check whether it's a new file and, if
    // so, consider it as of the right type

    if (Core::FileManager::instance()->isNew(nativeFileName))
        return true;

    // Check whether we are dealing with an empty file or a file that contains
    // spaces of sorts and, if not, whether we can load the file using the
    // standard and thus determine whether it is of the right type

    QString fileContents;

    if (Core::readTextFromFile(nativeFileName, fileContents)) {
        if (fileContents.trimmed().isEmpty())
            return true;

        return canLoadFile(nativeFileName);
    } else {
        return false;
    }
}

//==============================================================================

QObject * StandardFileManager::file(const QString &pFileName)
{
    // Return the File object, if any, associated with the given file

    return mFiles.value(Core::nativeCanonicalFileName(pFileName));
}

//==============================================================================

void StandardFileManager::manageFile(const QString &pFileName)
{
    QString nativeFileName = Core::nativeCanonicalFileName(pFileName);

    if (!file(nativeFileName) && isFile(nativeFileName)) {
        // We are dealing with a file, which is not already managed, so we can
        // add it to our list of managed files

        mFiles.insert(nativeFileName, newFile(nativeFileName));
    }
}

//==============================================================================

void StandardFileManager::unmanageFile(const QString &pFileName)
{
    QObject *crtFile = file(pFileName);

    if (crtFile) {
        // We are dealing with a file, so we can remove it from our list of
        // managed files after having deleted it

        delete crtFile;

        mFiles.remove(Core::nativeCanonicalFileName(pFileName));
    }
}

//==============================================================================

void StandardFileManager::reloadFile(const QString &pFileName)
{
    // The file is to be reloaded, so reload it
    // Note: to reload a file here ensures that our different standard-based
    //       views won't each do it, thus saving time and ensuring that a
    //       standard-based view doesn't forget to do it...

    QObject *crtFile = file(pFileName);

    if (crtFile) {
        // The file is managed, but should it still be (i.e. can it still be
        // considered as being a file)?

        if (isFile(pFileName))
            static_cast<StandardFile *>(crtFile)->reload();
        else
            unmanageFile(pFileName);
    } else {
        // The file is not managed, which means that previously it wasn't
        // considered as being a file, but things may be different now, so try
        // to remanage it and load it, if possible

        manageFile(pFileName);

        crtFile = file(pFileName);

        if (crtFile)
            static_cast<StandardFile *>(crtFile)->load();
    }
}

//==============================================================================

void StandardFileManager::renameFile(const QString &pOldFileName,
                                     const QString &pNewFileName)
{
    // The file has been renamed, so we need to update our files mapping, if
    // needed

    QObject *crtFile = file(pOldFileName);

    if (!crtFile)
        return;

    mFiles.insert(pNewFileName, crtFile);
    mFiles.remove(pOldFileName);

    // We also need to ensure that our file object has its file name updated

    static_cast<StandardFile *>(crtFile)->setFileName(pNewFileName);
}

//==============================================================================

}   // namespace StandardSupport
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you 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.

*******************************************************************************/

//==============================================================================
// Standard file manager
//==============================================================================

#include "corecliutils.h"
#include "filemanager.h"
#include "standardfilemanager.h"
#include "standardsupportplugin.h"

//==============================================================================

namespace OpenCOR {
namespace StandardSupport {

//==============================================================================

StandardFileManager::StandardFileManager() :
    mFiles(Files())
{
    // Create some connections to keep track of some events related to our
    // 'global' file manager

    Core::FileManager *fileManagerInstance = Core::FileManager::instance();

    connect(fileManagerInstance, SIGNAL(fileManaged(const QString &)),
            this, SLOT(manageFile(const QString &)));
    connect(fileManagerInstance, SIGNAL(fileUnmanaged(const QString &)),
            this, SLOT(unmanageFile(const QString &)));

    connect(fileManagerInstance, SIGNAL(fileReloaded(const QString &)),
            this, SLOT(reloadFile(const QString &)));

    connect(fileManagerInstance, SIGNAL(fileRenamed(const QString &, const QString &)),
            this, SLOT(renameFile(const QString &, const QString &)));
}

//==============================================================================

StandardFileManager::~StandardFileManager()
{
    // Remove all the managed files

    foreach (QObject *file, mFiles)
        delete file;
}

//==============================================================================

bool StandardFileManager::isFile(const QString &pFileName)
{
    // If the given file is already managed, then we consider that it's of the
    // right type (e.g. CellML file), even though it may not be of the right
    // type anymore after having been edited and saved, but in this case it's
    // good to keep considering the file as of the right type, so that the user
    // can continue editing it without any problem, for example

    QString nativeFileName = Core::nativeCanonicalFileName(pFileName);

    if (file(nativeFileName))
        return true;

    // The given file is not managed, so check whether it's a new file and, if
    // so, consider it as of the right type

    if (Core::FileManager::instance()->isNew(nativeFileName))
        return true;

    // Check whether we are dealing with an empty file or a file that contains
    // spaces of sorts and, if not, whether we can load the file using the
    // standard and thus determine whether it is of the right type

    QString fileContents;

    if (Core::readTextFromFile(nativeFileName, fileContents)) {
        if (fileContents.trimmed().isEmpty())
            return true;

        return canLoadFile(nativeFileName);
    } else {
        return false;
    }
}

//==============================================================================

QObject * StandardFileManager::file(const QString &pFileName)
{
    // Return the File object, if any, associated with the given file

    return mFiles.value(Core::nativeCanonicalFileName(pFileName));
}

//==============================================================================

void StandardFileManager::manageFile(const QString &pFileName)
{
    QString nativeFileName = Core::nativeCanonicalFileName(pFileName);

    if (!file(nativeFileName) && isFile(nativeFileName)) {
        // We are dealing with a file, which is not already managed, so we can
        // add it to our list of managed files

        mFiles.insert(nativeFileName, newFile(nativeFileName));
    }
}

//==============================================================================

void StandardFileManager::unmanageFile(const QString &pFileName)
{
    QObject *crtFile = file(pFileName);

    if (crtFile) {
        // We are dealing with a file, so we can remove it from our list of
        // managed files after having deleted it

        delete crtFile;

        mFiles.remove(Core::nativeCanonicalFileName(pFileName));
    }
}

//==============================================================================

void StandardFileManager::reloadFile(const QString &pFileName)
{
    // The file is to be reloaded, so reload it
    // Note: to reload a file here ensures that our different standard-based
    //       views won't each do it, thus saving time and ensuring that a
    //       standard-based view doesn't forget to do it...

    QObject *crtFile = file(pFileName);

    if (crtFile) {
        // The file is managed, but should it still be (i.e. can it still be
        // considered as being a file)?

        if (isFile(pFileName))
            static_cast<StandardFile *>(crtFile)->reload();
        else
            unmanageFile(pFileName);
    } else {
        // The file is not managed, which means that previously it wasn't
        // considered as being a file, but things may be different now, so try
        // to remanage it and load it, if possible

        manageFile(pFileName);

        crtFile = file(pFileName);

        if (crtFile)
            static_cast<StandardFile *>(crtFile)->load();
    }
}

//==============================================================================

void StandardFileManager::renameFile(const QString &pOldFileName,
                                     const QString &pNewFileName)
{
    // The file has been renamed, so we need to update our files mapping, if
    // needed

    QObject *crtFile = file(pOldFileName);

    if (!crtFile)
        return;

    mFiles.insert(pNewFileName, crtFile);
    mFiles.remove(pOldFileName);

    // We also need to ensure that our file object has its file name updated

    static_cast<StandardFile *>(crtFile)->setFileName(pNewFileName);
}

//==============================================================================

}   // namespace StandardSupport
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkDCMTKTransformIO.h"
#include "itkDCMTKTransformIOFactory.h"
#include "itkTransformFileReader.h"
#include "itkTestingMacros.h"
#include "itkCompositeTransform.h"

int itkDCMTKTransformIOTest( int argc, char* argv[] )
{
  if( argc < 2 )
    {
    std::cerr << "Usage: " << argv[0]
              << " transform" << std::endl;
    return EXIT_FAILURE;
    }
  const char * transformFileName = argv[1];

  constexpr unsigned int Dimension = 3;
  using ScalarType = float;

  itk::DCMTKTransformIOFactory::Pointer dcmtkTransformIOFactory = itk::DCMTKTransformIOFactory::New();
  EXERCISE_BASIC_OBJECT_METHODS( dcmtkTransformIOFactory, DCMTKTransformIOFactory, ObjectFactoryBase );
  std::cout << std::endl;
  itk::ObjectFactoryBase::RegisterFactory( dcmtkTransformIOFactory );

  using TransformReaderType = itk::TransformFileReaderTemplate< ScalarType >;
  TransformReaderType::Pointer transformReader = TransformReaderType::New();
  transformReader->SetFileName( transformFileName );

  using TransformIOType = itk::DCMTKTransformIO< ScalarType >;
  TransformIOType::Pointer transformIO = TransformIOType::New();
  EXERCISE_BASIC_OBJECT_METHODS( transformIO, DCMTKTransformIO, TransformIOBaseTemplate );
  transformReader->SetTransformIO( transformIO );

  TEST_EXPECT_TRUE( ! transformIO->CanWriteFile( transformFileName ) );

  TEST_EXPECT_TRUE( ! transformIO->CanReadFile( "fileThatDoesNotExist.dcm" ) );

  TEST_EXPECT_TRUE( transformIO->CanReadFile( transformFileName ) );

  TRY_EXPECT_EXCEPTION( transformIO->Write() );

  TRY_EXPECT_NO_EXCEPTION( transformReader->Update() );

  using TransformListType = TransformReaderType::TransformListType;
  const TransformListType * transformList = transformReader->GetTransformList();

  using ReadTransformType = itk::CompositeTransform< ScalarType, Dimension >;
  TransformListType::const_iterator transformIt = transformList->begin();
  ReadTransformType::Pointer readTransform = dynamic_cast< ReadTransformType * >( (*transformIt).GetPointer() );
  if( readTransform.IsNull() )
    {
    std::cerr << "Did not get the expected transform out." << std::endl;
    return EXIT_FAILURE;
    }
  readTransform->Print( std::cout );
  TEST_EXPECT_EQUAL( 3, transformIO->GetReadTransformList().size() );

  transformIO->SetFrameOfReferenceUID( "1.2.826.0.1.3680043.8.274.1.1.8323328.22085.1372783046.709932" );
  TRY_EXPECT_NO_EXCEPTION( transformReader->Update() );
  TEST_EXPECT_EQUAL( 2, transformIO->GetReadTransformList().size() );

  return EXIT_SUCCESS;
}
<commit_msg>COMP: Add const to non changing values.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkDCMTKTransformIO.h"
#include "itkDCMTKTransformIOFactory.h"
#include "itkTransformFileReader.h"
#include "itkTestingMacros.h"
#include "itkCompositeTransform.h"

int itkDCMTKTransformIOTest( int argc, char* argv[] )
{
  if( argc < 2 )
    {
    std::cerr << "Usage: " << argv[0]
              << " transform" << std::endl;
    return EXIT_FAILURE;
    }
  const char * transformFileName = argv[1];

  constexpr unsigned int Dimension = 3;
  using ScalarType = float;

  itk::DCMTKTransformIOFactory::Pointer dcmtkTransformIOFactory = itk::DCMTKTransformIOFactory::New();
  EXERCISE_BASIC_OBJECT_METHODS( dcmtkTransformIOFactory, DCMTKTransformIOFactory, ObjectFactoryBase );
  std::cout << std::endl;
  itk::ObjectFactoryBase::RegisterFactory( dcmtkTransformIOFactory );

  using TransformReaderType = itk::TransformFileReaderTemplate< ScalarType >;
  TransformReaderType::Pointer transformReader = TransformReaderType::New();
  transformReader->SetFileName( transformFileName );

  using TransformIOType = itk::DCMTKTransformIO< ScalarType >;
  TransformIOType::Pointer transformIO = TransformIOType::New();
  EXERCISE_BASIC_OBJECT_METHODS( transformIO, DCMTKTransformIO, TransformIOBaseTemplate );
  transformReader->SetTransformIO( transformIO );

  TEST_EXPECT_TRUE( ! transformIO->CanWriteFile( transformFileName ) );

  TEST_EXPECT_TRUE( ! transformIO->CanReadFile( "fileThatDoesNotExist.dcm" ) );

  TEST_EXPECT_TRUE( transformIO->CanReadFile( transformFileName ) );

  TRY_EXPECT_EXCEPTION( transformIO->Write() );

  TRY_EXPECT_NO_EXCEPTION( transformReader->Update() );

  using TransformListType = TransformReaderType::TransformListType;
  const TransformListType * const transformList = transformReader->GetTransformList();

  using ReadTransformType = itk::CompositeTransform< ScalarType, Dimension >;
  TransformListType::const_iterator transformIt = transformList->begin();
  ReadTransformType::Pointer readTransform = dynamic_cast< ReadTransformType * >( (*transformIt).GetPointer() );
  if( readTransform.IsNull() )
    {
    std::cerr << "Did not get the expected transform out." << std::endl;
    return EXIT_FAILURE;
    }
  readTransform->Print( std::cout );
  TEST_EXPECT_EQUAL( 3, transformIO->GetReadTransformList().size() );

  transformIO->SetFrameOfReferenceUID( "1.2.826.0.1.3680043.8.274.1.1.8323328.22085.1372783046.709932" );
  TRY_EXPECT_NO_EXCEPTION( transformReader->Update() );
  TEST_EXPECT_EQUAL( 2, transformIO->GetReadTransformList().size() );

  return EXIT_SUCCESS;
}
<|endoftext|>