<commit_before>/*

   Copyright 2014 The pydevs Developers

   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.

*/

#ifndef ADEVS_PYTHON_HPP
#define ADEVS_PYTHON_HPP

#include <functional>

#include <Python.h>

#include "adevs.h"
#include<iostream>

namespace pydevs {

typedef PyObject* Value;
typedef int Port;
typedef adevs::PortValue<Value, Port> PortValue;
typedef adevs::Bag<PortValue> IOBag;
typedef double Time;
typedef adevs::Atomic<PortValue, Time> AtomicBase;
typedef adevs::Digraph<Value, Port, Time> DigraphBase;
typedef adevs::Devs<PortValue, Time> Devs;
typedef adevs::Simulator<PortValue, Time> SimulatorBase;

typedef void (*DeltaIntFunc)(PyObject*);
typedef void (*DeltaExtFunc)(PyObject*, Time, const IOBag&);
typedef void (*DeltaConfFunc)(PyObject*, const IOBag&);
typedef void (*OutputFunc)(PyObject*, IOBag&);
typedef Time (*TaFunc)(PyObject*);

/**
 *	C++ wrapper class which implements the virtual functions
 *	of the adevs Atomic model
*/
class Atomic: public AtomicBase {

public:

	explicit Atomic(
		PyObject* pythonObject,
		DeltaIntFunc deltaIntFunc,
		DeltaExtFunc deltaExtFunc,
		DeltaConfFunc deltaConfFunc,
		OutputFunc outputFunc,
		TaFunc taFunc
	)
	: 	AtomicBase(),
		pythonObject_ (pythonObject),
		deltaIntFunc_ (deltaIntFunc),
		deltaExtFunc_ (deltaExtFunc),
		deltaConfFunc_ (deltaConfFunc),
		outputFunc_ (outputFunc),
		taFunc_ (taFunc)
	{ }

	/**
	 * Destructor
	 */
	virtual ~Atomic() { }

	virtual void delta_int() {

		bool isDefined = this->pythonObject_ && this->deltaIntFunc_;
		if (isDefined){
			this->deltaIntFunc_ (this->pythonObject_);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
			throw std::bad_function_call();

	}

	virtual void delta_ext (Time e, const IOBag& xb) {

		bool isDefined = this->pythonObject_ && this->deltaExtFunc_;
		if (isDefined){
			this->deltaExtFunc_ (this->pythonObject_, e, xb);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
			throw std::bad_function_call();

	}

	virtual void delta_conf (const IOBag& xb) {

		bool isDefined = this->pythonObject_ && this->deltaConfFunc_;
		if (isDefined){
			this->deltaConfFunc_ (this->pythonObject_, xb);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
			throw std::bad_function_call();
	}

	virtual void output_func (IOBag& yb) {

		bool isDefined = this->pythonObject_ && this->outputFunc_;
		if (isDefined)
		{
			this->outputFunc_ (this->pythonObject_, yb);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
		{
			throw std::bad_function_call();
		}

	}

	virtual Time ta() {

		bool isDefined = this->pythonObject_ && this->taFunc_;
		if (isDefined)
			return this->taFunc_ (this->pythonObject_);
		else
			throw std::bad_function_call();

	}

	/*
		garbage collection

		Decrease reference counters of all Python objects
	*/
	virtual void gc_output (IOBag& g) {

		for (auto& portValue : g) {
			Py_CLEAR (portValue.value);
		}

	}

	PyObject* getPythonObject() const {

		return this->pythonObject_;

	}

	std::string get_PyExceptionAsString()
	{
		// now we will try to get the python traceback.
		// see https://stackoverflow.com/questions/1796510/accessing-a-python-traceback-from-the-c-api
		// for longer discussion on how to do it.
		PyObject *ptype, *pvalue, *ptraceback;
		PyObject *pystr, *pystr_unic;

        std::string error_desc;
		PyErr_Fetch(&ptype, &pvalue, &ptraceback);
        if (pvalue == NULL){
            error_desc = {"No information on the occured exception available"};
        }
        else {
    		pystr = PyObject_Str(pvalue);
	    	pystr_unic = PyUnicode_AsEncodedString(pystr, "utf-8", "ignore");
		    error_desc = {PyBytes_AsString(pystr_unic)};

            Py_XDECREF(pystr);
	    	Py_XDECREF(pystr_unic);
        }
		Py_XDECREF(ptype);
		Py_XDECREF(pvalue);
		Py_XDECREF(ptraceback);

		return "Python traceback follows:\n" + error_desc;
	}

private:

	PyObject* const pythonObject_;
	const DeltaIntFunc deltaIntFunc_;
	const DeltaExtFunc deltaExtFunc_;
	const DeltaConfFunc deltaConfFunc_;
	const OutputFunc outputFunc_;
	const TaFunc taFunc_;
};

/**
 * C++ wrapper class for Digraph
 */
class Digraph {

public:

	typedef adevs::Set<Devs*> Components;

	/*
		Constructor
	*/
	explicit Digraph() : base_() {}

	DigraphBase& getBase() {

		return this->base_;

	}

	/**
	 * Add a DEVS model to the Digraph
	 *
	 * Currently, only atomic models are implemented.
	 */
	void add (Atomic* model) {

		this->base_.add (model);

	}

	/**
	 * Couple components
	 *
	 * Currently, only atomic models are implemented.
	 */
	void couple(
		Atomic* source, Port source_port,
		Atomic* destination, Port destination_port
	)
	{

		this->base_.couple(
			source, source_port,
			destination, destination_port
		);

	}

	void getComponents (Components& components) {

		this->base_.getComponents (components);

	}

private:

	DigraphBase base_;

};

/**
 *  C++ wrapper class for Simulator
 */
class Simulator {

public:

	/**
	 * Constructors
	 */
	explicit Simulator (Devs* model) : base_(model) {}

	explicit Simulator (Atomic* model) : base_(model) {}

	explicit Simulator (Digraph* digraph)
	: base_ (&digraph->getBase())
	{}

	SimulatorBase& getBase() {

		return this->base_;

	}

	Time nextEventTime() {

		return this->base_.nextEventTime();

	}

	void executeNextEvent() {

		this->base_.execNextEvent();

	}

	void executeUntil (Time tEnd) {

		this->base_.execUntil (tEnd);

	}

private:

	SimulatorBase base_;

};

} // namespace pydevs

# endif // ADEVS_PYTHON_HPP
<commit_msg>tab/space problems again<commit_after>/*

   Copyright 2014 The pydevs Developers

   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.

*/

#ifndef ADEVS_PYTHON_HPP
#define ADEVS_PYTHON_HPP

#include <functional>

#include <Python.h>

#include "adevs.h"
#include<iostream>

namespace pydevs {

typedef PyObject* Value;
typedef int Port;
typedef adevs::PortValue<Value, Port> PortValue;
typedef adevs::Bag<PortValue> IOBag;
typedef double Time;
typedef adevs::Atomic<PortValue, Time> AtomicBase;
typedef adevs::Digraph<Value, Port, Time> DigraphBase;
typedef adevs::Devs<PortValue, Time> Devs;
typedef adevs::Simulator<PortValue, Time> SimulatorBase;

typedef void (*DeltaIntFunc)(PyObject*);
typedef void (*DeltaExtFunc)(PyObject*, Time, const IOBag&);
typedef void (*DeltaConfFunc)(PyObject*, const IOBag&);
typedef void (*OutputFunc)(PyObject*, IOBag&);
typedef Time (*TaFunc)(PyObject*);

/**
 *	C++ wrapper class which implements the virtual functions
 *	of the adevs Atomic model
*/
class Atomic: public AtomicBase {

public:

	explicit Atomic(
		PyObject* pythonObject,
		DeltaIntFunc deltaIntFunc,
		DeltaExtFunc deltaExtFunc,
		DeltaConfFunc deltaConfFunc,
		OutputFunc outputFunc,
		TaFunc taFunc
	)
	: 	AtomicBase(),
		pythonObject_ (pythonObject),
		deltaIntFunc_ (deltaIntFunc),
		deltaExtFunc_ (deltaExtFunc),
		deltaConfFunc_ (deltaConfFunc),
		outputFunc_ (outputFunc),
		taFunc_ (taFunc)
	{ }

	/**
	 * Destructor
	 */
	virtual ~Atomic() { }

	virtual void delta_int() {

		bool isDefined = this->pythonObject_ && this->deltaIntFunc_;
		if (isDefined){
			this->deltaIntFunc_ (this->pythonObject_);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
			throw std::bad_function_call();

	}

	virtual void delta_ext (Time e, const IOBag& xb) {

		bool isDefined = this->pythonObject_ && this->deltaExtFunc_;
		if (isDefined){
			this->deltaExtFunc_ (this->pythonObject_, e, xb);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
			throw std::bad_function_call();

	}

	virtual void delta_conf (const IOBag& xb) {

		bool isDefined = this->pythonObject_ && this->deltaConfFunc_;
		if (isDefined){
			this->deltaConfFunc_ (this->pythonObject_, xb);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
			throw std::bad_function_call();
	}

	virtual void output_func (IOBag& yb) {

		bool isDefined = this->pythonObject_ && this->outputFunc_;
		if (isDefined)
		{
			this->outputFunc_ (this->pythonObject_, yb);
			if (PyErr_Occurred())
			{
				std::string error_message = get_PyExceptionAsString();
				throw std::runtime_error(error_message);
			}
		}
		else
		{
			throw std::bad_function_call();
		}

	}

	virtual Time ta() {

		bool isDefined = this->pythonObject_ && this->taFunc_;
		if (isDefined)
			return this->taFunc_ (this->pythonObject_);
		else
			throw std::bad_function_call();

	}

	/*
		garbage collection

		Decrease reference counters of all Python objects
	*/
	virtual void gc_output (IOBag& g) {

		for (auto& portValue : g) {
			Py_CLEAR (portValue.value);
		}

	}

	PyObject* getPythonObject() const {

		return this->pythonObject_;

	}

	std::string get_PyExceptionAsString()
	{
		// now we will try to get the python traceback.
		// see https://stackoverflow.com/questions/1796510/accessing-a-python-traceback-from-the-c-api
		// for longer discussion on how to do it.
		PyObject *ptype, *pvalue, *ptraceback;
		PyObject *pystr, *pystr_unic;

		std::string error_desc;
		PyErr_Fetch(&ptype, &pvalue, &ptraceback);
		if (pvalue == NULL){
			error_desc = {"No information on the occured exception available"};
		}
		else {
			pystr = PyObject_Str(pvalue);
			pystr_unic = PyUnicode_AsEncodedString(pystr, "utf-8", "ignore");
			error_desc = {PyBytes_AsString(pystr_unic)};

			Py_XDECREF(pystr);
			Py_XDECREF(pystr_unic);
		}
		Py_XDECREF(ptype);
		Py_XDECREF(pvalue);
		Py_XDECREF(ptraceback);

		return "Python traceback follows:\n" + error_desc;
	}

private:

	PyObject* const pythonObject_;
	const DeltaIntFunc deltaIntFunc_;
	const DeltaExtFunc deltaExtFunc_;
	const DeltaConfFunc deltaConfFunc_;
	const OutputFunc outputFunc_;
	const TaFunc taFunc_;
};

/**
 * C++ wrapper class for Digraph
 */
class Digraph {

public:

	typedef adevs::Set<Devs*> Components;

	/*
		Constructor
	*/
	explicit Digraph() : base_() {}

	DigraphBase& getBase() {

		return this->base_;

	}

	/**
	 * Add a DEVS model to the Digraph
	 *
	 * Currently, only atomic models are implemented.
	 */
	void add (Atomic* model) {

		this->base_.add (model);

	}

	/**
	 * Couple components
	 *
	 * Currently, only atomic models are implemented.
	 */
	void couple(
		Atomic* source, Port source_port,
		Atomic* destination, Port destination_port
	)
	{

		this->base_.couple(
			source, source_port,
			destination, destination_port
		);

	}

	void getComponents (Components& components) {

		this->base_.getComponents (components);

	}

private:

	DigraphBase base_;

};

/**
 *  C++ wrapper class for Simulator
 */
class Simulator {

public:

	/**
	 * Constructors
	 */
	explicit Simulator (Devs* model) : base_(model) {}

	explicit Simulator (Atomic* model) : base_(model) {}

	explicit Simulator (Digraph* digraph)
	: base_ (&digraph->getBase())
	{}

	SimulatorBase& getBase() {

		return this->base_;

	}

	Time nextEventTime() {

		return this->base_.nextEventTime();

	}

	void executeNextEvent() {

		this->base_.execNextEvent();

	}

	void executeUntil (Time tEnd) {

		this->base_.execUntil (tEnd);

	}

private:

	SimulatorBase base_;

};

} // namespace pydevs

# endif // ADEVS_PYTHON_HPP
<|endoftext|>


<commit_before>#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){
    ofEnableAntiAliasing();
    ofSetVerticalSync( true );
    ofSetFrameRate( 30 );

    #ifdef DISABLE_STREAMING
    cout << "Disabled streaming: compile with 'Release' to enable" << endl;
    #else
    cout << "Enabled streaming: compile with 'Release NoStream' to disable" << endl;
    #endif

    ofSetLogLevel( OF_LOG_WARNING );
    w = 640;
    h = 480;
    int flowW = w/4;
    int flowH = h/4;

    videoFeedController.init();

    vfx1.init();
    vfx1.setVideoSource( videoFeedController.videoSource );

    vfx1.setColor( colors[colorIndex] );

    big = &vfx1;

    videoFXExporter.setVideoFX( &vfx1 );

    overlay.init();

    websystemController.setVideoFX( &vfx1 );
    websystemController.setOverlay( &overlay );
    websystemController.init();

#ifndef DISABLE_STREAMING
    // MULTI STREAMER
    // --------------------------------------------------
    int fps = 15;
    if(!streamer.setup("streamer.xml", ofGetWidth(), ofGetHeight(), fps)) {
      printf("error: cannot setup the streamer.\n");
      ::exit(EXIT_FAILURE);
    }

    if(!streamer.start()) {
      printf("error: cannot start the streamer.\n");
      ::exit(EXIT_FAILURE);
    }

    sound_stream.listDevices();
    sound_stream.setup(this, 0, 2, 44100, 1024, 4);
#endif

}

void testApp::audioIn(float* input, int nsize, int nchannels) {

#ifndef DISABLE_STREAMING
    size_t nsamples = nsize * nchannels;
    for(size_t i = 0; i < nsamples; ++i) {
        input[i] *= 32768.0f;
    }

    //streamer.addAudio(input, nsize, nchannels);
#endif
}

//--------------------------------------------------------------
void testApp::update(){
    if (ofGetElapsedTimef() < 2.0f) { return; }

#ifndef DISABLE_STREAMING
    streamer.update();
#endif

    websystemController.update();

    videoFeedController.update();

    vfx1.setVideoSource( videoFeedController.videoSource );
    vfx1.update( videoFeedController.videoSource->isFrameNew() );

    overlay.update();
}

//--------------------------------------------------------------
void testApp::draw(){
    if (ofGetElapsedTimef() < 2.0f) { return; }

#ifndef DISABLE_STREAMING
    if(streamer.wantsNewFrame()) {
        streamer.beginGrab();
            drawInternal();
        streamer.endGrab();
    }
#endif

    drawInternal();
    cout << "framerate " << ofGetFrameRate() << endl;
}

void testApp::drawInternal() {

    big->draw( ofGetWidth(), 0, -ofGetWidth(), ofGetHeight() );

    overlay.draw();

    // Screen shot saving
    string nextScreenshotName = websystemController.getNextScreenShotFilename();
    if ( nextScreenshotName != "" ) {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glReadBuffer(GL_BACK);
        glPixelStorei(GL_PACK_ALIGNMENT, 4);
        //Saving
        ofSaveViewport("screenshots/" + nextScreenshotName + ".png");
        //ofSaveScreen( "screenshots/" + nextScreenshotName + ".png");
    }
}

//--------------------------------------------------------------
void testApp::keyPressed(int key) {

    cout << key << endl;

    if ( key == 'a' ) {
        overlay.voteDisplay.addVote( overlay.voteDisplay.topic1 );
    }
    else if ( key == 'b' ) {
        overlay.voteDisplay.addVote( overlay.voteDisplay.topic2 );
    }

    if ( key == 'k' ) {
        vfx1.reloadShaders();
    }
    else if ( key == 161 ) { // tilda key
        big->hideGUI();
        videoFXExporter.exporterGUI->setVisible( false );
        overlay.overlayGUI->setVisible( false );
    }
    else if ( key == '1' ) {
        big = &vfx1;
        big->showGUI();
        videoFXExporter.exporterGUI->setVisible( true );
        overlay.overlayGUI->setVisible( true );
    }
    else if ( key == 45 ) {
        if ( --colorIndex < 0 )
            colorIndex = 6;
        vfx1.setColor( colors[colorIndex] );
    }
    else if ( key == 61 ) {
        if ( ++colorIndex > 6 )
            colorIndex = 0;
        vfx1.setColor( colors[colorIndex] );
    }
}

//--------------------------------------------------------------
void testApp::keyReleased(int key){

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void testApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void testApp::dragEvent(ofDragInfo dragInfo){

}

void testApp::exit() {
    vfx1.exit();
    videoFXExporter.exporterGUI->saveSettings("GUI/exporter.xml");
    overlay.overlayGUI->saveSettings( "GUI/overlay.xml" );
}
<commit_msg>Removed legacy<commit_after>#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){
    ofEnableAntiAliasing();
    ofSetVerticalSync( true );
    ofSetFrameRate( 30 );

    #ifdef DISABLE_STREAMING
    cout << "Disabled streaming: compile with 'Release' to enable" << endl;
    #else
    cout << "Enabled streaming: compile with 'Release NoStream' to disable" << endl;
    #endif

    ofSetLogLevel( OF_LOG_WARNING );

    videoFeedController.init();

    vfx1.init();
    vfx1.setVideoSource( videoFeedController.videoSource );

    vfx1.setColor( colors[colorIndex] );

    big = &vfx1;

    videoFXExporter.setVideoFX( &vfx1 );

    overlay.init();

    websystemController.setVideoFX( &vfx1 );
    websystemController.setOverlay( &overlay );
    websystemController.init();

#ifndef DISABLE_STREAMING
    // MULTI STREAMER
    // --------------------------------------------------
    int fps = 15;
    if(!streamer.setup("streamer.xml", ofGetWidth(), ofGetHeight(), fps)) {
      printf("error: cannot setup the streamer.\n");
      ::exit(EXIT_FAILURE);
    }

    if(!streamer.start()) {
      printf("error: cannot start the streamer.\n");
      ::exit(EXIT_FAILURE);
    }

    sound_stream.listDevices();
    sound_stream.setup(this, 0, 2, 44100, 1024, 4);
#endif

}

void testApp::audioIn(float* input, int nsize, int nchannels) {

#ifndef DISABLE_STREAMING
    size_t nsamples = nsize * nchannels;
    for(size_t i = 0; i < nsamples; ++i) {
        input[i] *= 32768.0f;
    }

    //streamer.addAudio(input, nsize, nchannels);
#endif
}

//--------------------------------------------------------------
void testApp::update(){
    if (ofGetElapsedTimef() < 2.0f) { return; }

#ifndef DISABLE_STREAMING
    streamer.update();
#endif

    websystemController.update();

    videoFeedController.update();

    vfx1.setVideoSource( videoFeedController.videoSource );
    vfx1.update( videoFeedController.videoSource->isFrameNew() );

    overlay.update();
}

//--------------------------------------------------------------
void testApp::draw(){
    if (ofGetElapsedTimef() < 2.0f) { return; }

#ifndef DISABLE_STREAMING
    if(streamer.wantsNewFrame()) {
        streamer.beginGrab();
            drawInternal();
        streamer.endGrab();
    }
#endif

    drawInternal();
    cout << "framerate " << ofGetFrameRate() << endl;
}

void testApp::drawInternal() {

    big->draw( ofGetWidth(), 0, -ofGetWidth(), ofGetHeight() );

    overlay.draw();

    // Screen shot saving
    string nextScreenshotName = websystemController.getNextScreenShotFilename();
    if ( nextScreenshotName != "" ) {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glReadBuffer(GL_BACK);
        glPixelStorei(GL_PACK_ALIGNMENT, 4);
        //Saving
        ofSaveViewport("screenshots/" + nextScreenshotName + ".png");
        //ofSaveScreen( "screenshots/" + nextScreenshotName + ".png");
    }
}

//--------------------------------------------------------------
void testApp::keyPressed(int key) {

    cout << key << endl;

    if ( key == 'a' ) {
        overlay.voteDisplay.addVote( overlay.voteDisplay.topic1 );
    }
    else if ( key == 'b' ) {
        overlay.voteDisplay.addVote( overlay.voteDisplay.topic2 );
    }

    if ( key == 'k' ) {
        vfx1.reloadShaders();
    }
    else if ( key == 161 ) { // tilda key
        big->hideGUI();
        videoFXExporter.exporterGUI->setVisible( false );
        overlay.overlayGUI->setVisible( false );
    }
    else if ( key == '1' ) {
        big = &vfx1;
        big->showGUI();
        videoFXExporter.exporterGUI->setVisible( true );
        overlay.overlayGUI->setVisible( true );
    }
    else if ( key == 45 ) {
        if ( --colorIndex < 0 )
            colorIndex = 6;
        vfx1.setColor( colors[colorIndex] );
    }
    else if ( key == 61 ) {
        if ( ++colorIndex > 6 )
            colorIndex = 0;
        vfx1.setColor( colors[colorIndex] );
    }
}

//--------------------------------------------------------------
void testApp::keyReleased(int key){

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void testApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void testApp::dragEvent(ofDragInfo dragInfo){

}

void testApp::exit() {
    vfx1.exit();
    videoFXExporter.exporterGUI->saveSettings("GUI/exporter.xml");
    overlay.overlayGUI->saveSettings( "GUI/overlay.xml" );
}
<|endoftext|>


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

   ID: mathema6
   TASK: B2
   LANG: C++14

   * File Name : B2.cpp
   * Creation Date : 15-07-2021
   * Last Modified : Thu 15 Jul 2021 12:45:26 AM CEST
   * Created By : Karel Ha <mathemage@gmail.com>
   * URL : https://codingcompetitions.withgoogle.com/kickstart/round/00000000004361e3/000000000082b933
   * Points/Time :
   * +16m
   * +
   *
   * Total/ETA : 17m
   * Status :
   *
   ==========================================*/

#define PROBLEMNAME "B2"

#include <bits/stdc++.h>

using namespace std;

#define endl "\n"
#define REP(i,n) for(ll i=0;i<(n);i++)
#define FOR(i,a,b) for(ll i=(a);i<=(b);i++)
#define FORD(i,a,b) for(ll i=(a);i>=(b);i--)
#define REPi(i,n) for(int i=0;i<(n);i++)
#define FORi(i,a,b) for(int i=(a);i<=(b);i++)
#define FORDi(i,a,b) for(int i=(a);i>=(b);i--)
#define ALL(A)     (A).begin(), (A).end()
#define REVALL(A)     (A).rbegin(), (A).rend()
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MTP make_tuple
#define SGN(X) ((X) ? ( (X)>0?1:-1 ) : 0)
#define CONTAINS(S,E) ((S).find(E) != (S).end())
#define SZ(x) ((int) (x).size())
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
#define YN(b) cout << ((b)?"YES":"NO") << endl;
#define Yes cout << "Yes" << endl;
#define No cout << "No" << endl;
#define Yn(b) cout << ((b)?"Yes":"No") << endl;

using ll = long long;
using ul = unsigned long long;
using llll = pair<ll, ll>;
using ulul = pair<ul, ul>;
using ld = long double;

#ifdef ONLINE_JUDGE
  #undef MATHEMAGE_DEBUG
#endif

#ifdef MATHEMAGE_DEBUG
  #define MSG(a) cerr << "> " << (#a) << ": " << (a) << endl;
  #define MSG_VEC_VEC(v) cerr << "> " << (#v) << ":\n" << (v) << endl;
  #define LINESEP1 cerr << "-----------------------------------------------                  " << endl;
  #define LINESEP2 cerr << "_________________________________________________________________" << endl;
#else
  #define MSG(a)
  #define MSG_VEC_VEC(v)
  #define LINESEP1
  #define LINESEP2
#endif

ostream& operator<<(ostream& os, const vector<string> & vec) { os << endl; for (const auto & s: vec) os << s << endl; return os; }

template<typename T>
ostream& operator<<(ostream& os, const vector<T> & vec) { for (const auto & x: vec) os << x << " "; return os; }

template<typename T>
ostream& operator<<(ostream& os, const vector<vector<T>> & vec) { for (const auto & v: vec) os << v << endl; return os; }

template<typename T>
inline ostream& operator<<(ostream& os, const vector<vector<vector<T>>> & vec) {
  for (const auto & row: vec) {
    for (const auto & col: row) {
      os << "[ " << col << "]   ";
    }
    os << endl;
  }
  return os;
}

template<typename T, class Compare>
ostream& operator<<(ostream& os, const set<T, Compare>& vec) { for (const auto & x: vec) os << x << " "; os << endl; return os; }

template<typename T, class Compare>
ostream& operator<<(ostream& os, const multiset<T, Compare>& vec) { for (const auto & x: vec) os << x << " "; os << endl; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const map<T1, T2>& vec) { for (const auto & x: vec) os << x.F << ":" << x.S << " | "; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const map<T1, T2, greater<T1>>& vec) { for (const auto & x: vec) os << x.F << ":" << x.S << " | "; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const unordered_map<T1, T2>& vec) { for (const auto & x: vec) os << x.F << ":" << x.S << " | "; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) { return os << "(" << p.F << ", " << p.S << ")"; }

template<typename T>
istream& operator>>(istream& is, vector<T> & vec) { for (auto & x: vec) is >> x; return is; }

template<typename T>
inline bool bounded(const T & x, const T & u, const T & l=0) { return min(l,u)<=x && x<max(l,u); }

template<class T> bool umin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool umax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

inline bool eqDouble(double a, double b) { return fabs(a-b) < 1e-9; }

const int CLEAN = -1;
const int UNDEF = -42;
const long long MOD = 1000000007;
const double EPS = 1e-8;

const int INF = INT_MAX;
const long long INF_LL = LLONG_MAX;
const long long INF_ULL = ULLONG_MAX;

const vector<int> DX4 = {0, 1,  0, -1};
const vector<int> DY4 = {1, 0, -1,  0};
const vector<pair<int,int>> DXY4 = { {0,1}, {1,0}, {0,-1}, {-1,0} };
const string dues="NESW";

const vector<int> DX8 = {-1, -1, -1,   0, 0,   1,  1,  1};
const vector<int> DY8 = {-1,  0,  1,  -1, 1,  -1,  0,  1};
const vector<pair<int,int>> DXY8 = {
  {-1,-1}, {-1,0}, {-1,1},
  { 0,-1},         { 0,1},
  { 1,-1}, { 1,0}, { 1,1}
};

#ifndef MATHEMAGE_LOCAL
void setIO(string filename) {    // the argument is the filename without the extension
	freopen((filename+".in").c_str(), "r", stdin);
	freopen((filename+".out").c_str(), "w", stdout);
  MSG(filename);
}
#endif

void solve() {
  ll N,C; cin >> N >> C;
  MSG(N); MSG(C); LINESEP1;

  ll Li,Ri;
  map<ll, ll> balance;
  map<ll, ll> boundary2count;
  REP(_,N) {
    cin >> Li >> Ri;
    balance[Li]++;
    balance[Ri]--;

    boundary2count[Li]++;
    boundary2count[Ri]++;
  }
  MSG(balance); MSG(boundary2count); LINESEP1;

  map<ll, ll, greater<ll>> thick2count;
  ll prvPt=balance.begin()->F;
  ll curThickness=0;
  for (auto & ptBal: balance) {
    MSG(prvPt); MSG(curThickness);

    ll span=ptBal.F-prvPt-2;
    if (span>0 && curThickness>0) {
      thick2count[curThickness]+=span;
    }

    ll boundaryThickness = curThickness - boundary2count[ptBal.F];
    if (boundaryThickness>0) {
      thick2count[boundaryThickness]++;
    }

    prvPt=ptBal.F;
    curThickness+=ptBal.S;
    MSG(prvPt); MSG(curThickness);
    LINESEP1;
  }
  MSG(thick2count);
  assert(curThickness==0);
  LINESEP1;

  ll result = N;
  cout << result << endl;
}

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout << std::setprecision(10) << std::fixed;

#ifndef MATHEMAGE_LOCAL
//   setIO(PROBLEMNAME);
#endif

  int cases = 1;
  cin >> cases;
  FOR(tt,1,cases) {
    cout << "Case #" << tt << ": ";
    solve();
    LINESEP2;
  }
  return 0;
}
<commit_msg>Upsolve GKickStart '21D, B. Cutting Intervals<commit_after>/* ========================================

   ID: mathema6
   TASK: B2
   LANG: C++14

   * File Name : B2.cpp
   * Creation Date : 15-07-2021
   * Last Modified : Thu 15 Jul 2021 05:51:01 PM CEST
   * Created By : Karel Ha <mathemage@gmail.com>
   * URL : https://codingcompetitions.withgoogle.com/kickstart/round/00000000004361e3/000000000082b933
   * Points/Time :
   * +16m
   * +10m ~ 26m
   *
   * Total/ETA : 17m
   * Status :
   * [redesign algo]
   * S AC AC !!! yes!
   *
   ==========================================*/

#define PROBLEMNAME "B2"

#include <bits/stdc++.h>

using namespace std;

#define endl "\n"
#define REP(i,n) for(ll i=0;i<(n);i++)
#define FOR(i,a,b) for(ll i=(a);i<=(b);i++)
#define FORD(i,a,b) for(ll i=(a);i>=(b);i--)
#define REPi(i,n) for(int i=0;i<(n);i++)
#define FORi(i,a,b) for(int i=(a);i<=(b);i++)
#define FORDi(i,a,b) for(int i=(a);i>=(b);i--)
#define ALL(A)     (A).begin(), (A).end()
#define REVALL(A)     (A).rbegin(), (A).rend()
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MTP make_tuple
#define SGN(X) ((X) ? ( (X)>0?1:-1 ) : 0)
#define CONTAINS(S,E) ((S).find(E) != (S).end())
#define SZ(x) ((int) (x).size())
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
#define YN(b) cout << ((b)?"YES":"NO") << endl;
#define Yes cout << "Yes" << endl;
#define No cout << "No" << endl;
#define Yn(b) cout << ((b)?"Yes":"No") << endl;

using ll = long long;
using ul = unsigned long long;
using llll = pair<ll, ll>;
using ulul = pair<ul, ul>;
using ld = long double;

#ifdef ONLINE_JUDGE
  #undef MATHEMAGE_DEBUG
#endif

#ifdef MATHEMAGE_DEBUG
  #define MSG(a) cerr << "> " << (#a) << ": " << (a) << endl;
  #define MSG_VEC_VEC(v) cerr << "> " << (#v) << ":\n" << (v) << endl;
  #define LINESEP1 cerr << "-----------------------------------------------                  " << endl;
  #define LINESEP2 cerr << "_________________________________________________________________" << endl;
#else
  #define MSG(a)
  #define MSG_VEC_VEC(v)
  #define LINESEP1
  #define LINESEP2
#endif

ostream& operator<<(ostream& os, const vector<string> & vec) { os << endl; for (const auto & s: vec) os << s << endl; return os; }

template<typename T>
ostream& operator<<(ostream& os, const vector<T> & vec) { for (const auto & x: vec) os << x << " "; return os; }

template<typename T>
ostream& operator<<(ostream& os, const vector<vector<T>> & vec) { for (const auto & v: vec) os << v << endl; return os; }

template<typename T>
inline ostream& operator<<(ostream& os, const vector<vector<vector<T>>> & vec) {
  for (const auto & row: vec) {
    for (const auto & col: row) {
      os << "[ " << col << "]   ";
    }
    os << endl;
  }
  return os;
}

template<typename T, class Compare>
ostream& operator<<(ostream& os, const set<T, Compare>& vec) { for (const auto & x: vec) os << x << " "; os << endl; return os; }

template<typename T, class Compare>
ostream& operator<<(ostream& os, const multiset<T, Compare>& vec) { for (const auto & x: vec) os << x << " "; os << endl; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const map<T1, T2>& vec) { for (const auto & x: vec) os << x.F << ":" << x.S << " | "; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const map<T1, T2, greater<T1>>& vec) { for (const auto & x: vec) os << x.F << ":" << x.S << " | "; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const unordered_map<T1, T2>& vec) { for (const auto & x: vec) os << x.F << ":" << x.S << " | "; return os; }

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) { return os << "(" << p.F << ", " << p.S << ")"; }

template<typename T>
istream& operator>>(istream& is, vector<T> & vec) { for (auto & x: vec) is >> x; return is; }

template<typename T>
inline bool bounded(const T & x, const T & u, const T & l=0) { return min(l,u)<=x && x<max(l,u); }

template<class T> bool umin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool umax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

inline bool eqDouble(double a, double b) { return fabs(a-b) < 1e-9; }

const int CLEAN = -1;
const int UNDEF = -42;
const long long MOD = 1000000007;
const double EPS = 1e-8;

const int INF = INT_MAX;
const long long INF_LL = LLONG_MAX;
const long long INF_ULL = ULLONG_MAX;

const vector<int> DX4 = {0, 1,  0, -1};
const vector<int> DY4 = {1, 0, -1,  0};
const vector<pair<int,int>> DXY4 = { {0,1}, {1,0}, {0,-1}, {-1,0} };
const string dues="NESW";

const vector<int> DX8 = {-1, -1, -1,   0, 0,   1,  1,  1};
const vector<int> DY8 = {-1,  0,  1,  -1, 1,  -1,  0,  1};
const vector<pair<int,int>> DXY8 = {
  {-1,-1}, {-1,0}, {-1,1},
  { 0,-1},         { 0,1},
  { 1,-1}, { 1,0}, { 1,1}
};

#ifndef MATHEMAGE_LOCAL
void setIO(string filename) {    // the argument is the filename without the extension
	freopen((filename+".in").c_str(), "r", stdin);
	freopen((filename+".out").c_str(), "w", stdout);
  MSG(filename);
}
#endif

#define OP first
#define CL second

void solve() {
  ll N,C; cin >> N >> C;
  MSG(N); MSG(C); LINESEP1;

  ll Li,Ri;
  map<ll, llll> balance;
  set<long long> pts;
  REP(_,N) {
    cin >> Li >> Ri;
    balance[Li].OP++;
    balance[Ri].CL++;

    pts.insert(Li);
    pts.insert(Ri);
  }
  MSG(balance); MSG(pts); LINESEP1;

  map<ll, ll, greater<ll>> thick2count;
  ll prvPt=UNDEF;
  ll curThickness=0;
  for (auto & pt: pts) {
    MSG(prvPt); MSG(curThickness);

    // interior
    ll span=pt-prvPt-1;
    if (span>0 && curThickness>0) {
      thick2count[curThickness]+=span;
    }

    // boundary
    curThickness-=balance[pt].CL;
    if (curThickness>0) {
      thick2count[curThickness]++;
    }

    prvPt=pt;
    curThickness+=balance[pt].OP;
    MSG(prvPt); MSG(curThickness);
    LINESEP1;
  }
  MSG(thick2count);
  assert(curThickness==0);
  LINESEP1;

  ll result = N;
  for (auto & thickCnt: thick2count) {
    ll delta=min(C, thickCnt.S);

    result+=delta*thickCnt.F;

    C-=delta;
    if (C<=0) {
      break;
    }
  }

  cout << result << endl;
}

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout << std::setprecision(10) << std::fixed;

#ifndef MATHEMAGE_LOCAL
//   setIO(PROBLEMNAME);
#endif

  int cases = 1;
  cin >> cases;
  FOR(tt,1,cases) {
    cout << "Case #" << tt << ": ";
    solve();
    LINESEP2;
  }
  return 0;
}
<|endoftext|>


<commit_before>#include "ncd_gateway.h"
#include "S3B.h"
#include "spark_wiring_eeprom.h"

S3B sModule;
String eventReturns[5];
unsigned long tOut = 3000;

//int s3b(JsonObject& root);

void init_gateway(){
    Particle.function("deviceComm", gatewayCommand);
    Particle.subscribe("ncd_deviceCom", commandHandler, MY_DEVICES);
    Serial1.begin(115200);
    Wire.begin();
}

int gatewayCommand(String arg){
    int length = arg.length();

    byte bytes[length+1];

    arg.getBytes(bytes, length+1);

    int newLen = (length/2)+1;

    byte newBytes[newLen];

    int ind = 0;

    for(int i=0;i<length;i+=2){
        if(i>0){
            ind=i/2;
        }
        int b1=(bytes[i]-32) << 4;
        int b2=bytes[i+1]-32;
        newBytes[ind]=b1+b2;
    }
    //send int pointer for setting to allow me to test how to return results?
    return ncdApi(newBytes);
}

void commandHandler(const char *event, const char *data){
    Serial.println("Got Event "+String(event));
    String newCommand = String(data);
    gatewayCommand(newCommand);
}
int ncdApi(byte packetBytes[]){
    int buffLen = 1;
    Serial.println(String(packetBytes[0]));
    switch(packetBytes[0]){
        case 187:
            {
                //packet of packets
                int i=2;
                int max;
                for(int pn = 0; pn<packetBytes[1]; pn++){

                    max=i+packetBytes[i];
                    Serial.println(max);
                    byte intPacket[packetBytes[i]];
                    i++;
                    int ni=0;
                    for(i;i<=max;i++){
                        intPacket[ni]=packetBytes[i];
                        ni++;
                    }
                    ncdApi(intPacket);
                }
                break;
            }
        case 188:
            {
                //plain i2c w/r command
                if(packetBytes[3] > 0){
                    buffLen = packetBytes[3];
                }
                byte buff[buffLen];
                i2c_command(packetBytes, buff);
                break;
            }
        case 189:
            {
                //masking command
                int addr = packetBytes[1];
                int maskOp = packetBytes[2];
                int maskedOffsets = packetBytes[3];
                int readCommandLen = packetBytes[4];
                int readLen = packetBytes[5];
                int readCommand[readCommandLen];

                array_slice(packetBytes, 6, readCommandLen, readCommand);

                int writeCommandLen = packetBytes[6+readCommandLen];
                int writeCommand[writeCommandLen];

                array_slice(packetBytes, 7+readCommandLen, writeCommandLen, writeCommand);

                int writeVals[writeCommandLen];
                int wi=0;
                for(wi; wi<maskedOffsets; wi++){
                    writeVals[wi]=writeCommand[wi];
                    Serial.println(writeVals[wi]);
                }

                writeCommandsI2C(addr, readCommand, readCommandLen);
                Wire.requestFrom(addr, readLen);
                for(int i=0;i<readLen;i++){
                    int current = Wire.read();
                    writeVals[wi] = mask(current, writeCommand[wi], maskOp);
                    Serial.println(current);
                    Serial.println(writeVals[wi]);
                    wi++;
                }

                writeCommandsI2C(addr, writeVals, writeCommandLen);
                break;
            }
    }
    return 1;
}
int mask(int val, int mask, int type){
    switch(type){
        case 0:
            val |= mask;
            break;
        case 1:
            val ^= mask;
            break;
        case 2:
            val &= ~mask;
            break;
        case 3:
            val &= mask;
            break;
        case 4:
            val = val << mask;
            break;
        case 5:
            val = val >> mask;
    }
    return val;
}
void i2c_command(byte bytes[], byte *buff){
    if(bytes[0] == 188){
        int commands[bytes[2]];
        array_slice(bytes, 4, bytes[2], commands);
        int addr = bytes[1];
        if(bytes[3] == 0){
            //write command
            buff[0]=writeCommandsI2C(addr, commands, bytes[2]);
        }else{
            //read command
            writeCommandsI2C(addr, commands, bytes[2]);
            Wire.requestFrom(addr, bytes[3]);
            for(int i=0;i<bytes[3];i++){
                buff[i] = Wire.read();
            }
        }
    }
}
void array_slice(byte bytes[], int start, int len, byte *buff){
    int ni = 0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
void array_slice(byte bytes[], int start, int len, int *buff){
    int ni=0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
int sendEvent(String key){
    int i = key.toInt();
    String eventName = "";
    eventName = "eventReturn_"+key;
    Particle.publish(eventName, eventReturns[i], 60, PRIVATE);
    eventReturns[i] = "";
    return 1;
};
int setEventReturn(String value){
    int index = 0;
    while(eventReturns[index].length() > 1){
        index++;
    }
    eventReturns[index] = value;
    return index;
};
int writeCommandsI2C(int addr, int* commands, int commandsLen){
    Serial.printf("Running I2C Command, address: %i data: ",addr);
    Wire.beginTransmission(addr);
    for(int i = 0; i < commandsLen; i++){
        Wire.write(commands[i]);
        Serial.printf("%i, ",commands[i]);
    }
    int status = Wire.endTransmission();
    Serial.printf(" Status: %i \n", status);
    return status;
};

<commit_msg>Update ncd_gateway.cpp<commit_after>#include "ncd_gateway.h"
#include "S3B.h"
#include "spark_wiring_eeprom.h"

S3B sModule;
String eventReturns[5];
unsigned long tOut = 3000;

//int s3b(JsonObject& root);

void init_gateway(){
    Particle.function("deviceComm", gatewayCommand);
    Particle.subscribe("ncd_deviceCom", commandHandler, MY_DEVICES);
    Serial1.begin(115200);
    Wire.begin();
}

int gatewayCommand(String arg){
    int length = arg.length();

    byte bytes[length+1];

    arg.getBytes(bytes, length+1);

    int newLen = (length/2)+1;

    byte newBytes[newLen];

    int ind = 0;

    for(int i=0;i<length;i+=2){
        if(i>0){
            ind=i/2;
        }
        int b1=(bytes[i]-32) << 4;
        int b2=bytes[i+1]-32;
        newBytes[ind]=b1+b2;
    }
    //send int pointer for setting to allow me to test how to return results?
    return ncdApi(newBytes);
}

void commandHandler(const char *event, const char *data){
    Serial.println("Got Event "+String(event));
    String newCommand = String(data);
    gatewayCommand(newCommand);
}
int ncdApi(byte packetBytes[]){
    int buffLen = 1;
    Serial.println(String(packetBytes[0]));
    switch(packetBytes[0]){
        case 187:
            {
                //packet of packets
                int i=2;
                int max;
                for(int pn = 0; pn<packetBytes[1]; pn++){

                    max=i+packetBytes[i];
                    Serial.println(max);
                    byte intPacket[packetBytes[i]];
                    i++;
                    int ni=0;
                    for(i;i<=max;i++){
                        intPacket[ni]=packetBytes[i];
                        ni++;
                    }
                    ncdApi(intPacket);
                }
                break;
            }
        case 188:
            {
                //plain i2c w/r command
                if(packetBytes[3] > 0){
                    buffLen = packetBytes[3];
                    byte buff[buffLen];
                    i2c_command(packetBytes, buff);
                }
                return bytesToInt(buff, buffLen);
            }
        case 189:
            {
                //masking command
                int addr = packetBytes[1];
                int maskOp = packetBytes[2];
                int maskedOffsets = packetBytes[3];
                int readCommandLen = packetBytes[4];
                int readLen = packetBytes[5];
                int readCommand[readCommandLen];

                array_slice(packetBytes, 6, readCommandLen, readCommand);

                int writeCommandLen = packetBytes[6+readCommandLen];
                int writeCommand[writeCommandLen];

                array_slice(packetBytes, 7+readCommandLen, writeCommandLen, writeCommand);

                int writeVals[writeCommandLen];
                int wi=0;
                for(wi; wi<maskedOffsets; wi++){
                    writeVals[wi]=writeCommand[wi];
                    Serial.println(writeVals[wi]);
                }

                writeCommandsI2C(addr, readCommand, readCommandLen);
                Wire.requestFrom(addr, readLen);
                for(int i=0;i<readLen;i++){
                    int current = Wire.read();
                    writeVals[wi] = mask(current, writeCommand[wi], maskOp);
                    Serial.println(current);
                    Serial.println(writeVals[wi]);
                    wi++;
                }

                writeCommandsI2C(addr, writeVals, writeCommandLen);
                break;
            }
    }
    return 1;
}
int mask(int val, int mask, int type){
    switch(type){
        case 0:
            val |= mask;
            break;
        case 1:
            val ^= mask;
            break;
        case 2:
            val &= ~mask;
            break;
        case 3:
            val &= mask;
            break;
        case 4:
            val = val << mask;
            break;
        case 5:
            val = val >> mask;
    }
    return val;
}
void i2c_command(byte bytes[], byte *buff){
    if(bytes[0] == 188){
        int commands[bytes[2]];
        array_slice(bytes, 4, bytes[2], commands);
        int addr = bytes[1];
        if(bytes[3] == 0){
            //write command
            buff[0]=writeCommandsI2C(addr, commands, bytes[2]);
        }else{
            //read command
            writeCommandsI2C(addr, commands, bytes[2]);
            Wire.requestFrom(addr, bytes[3]);
            for(int i=0;i<bytes[3];i++){
                buff[i] = Wire.read();
            }
        }
    }
}
void array_slice(byte bytes[], int start, int len, byte *buff){
    int ni = 0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
void array_slice(byte bytes[], int start, int len, int *buff){
    int ni=0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
int sendEvent(String key){
    int i = key.toInt();
    String eventName = "";
    eventName = "eventReturn_"+key;
    Particle.publish(eventName, eventReturns[i], 60, PRIVATE);
    eventReturns[i] = "";
    return 1;
};
int setEventReturn(String value){
    int index = 0;
    while(eventReturns[index].length() > 1){
        index++;
    }
    eventReturns[index] = value;
    return index;
};
int writeCommandsI2C(int addr, int* commands, int commandsLen){
    Serial.printf("Running I2C Command, address: %i data: ",addr);
    Wire.beginTransmission(addr);
    for(int i = 0; i < commandsLen; i++){
        Wire.write(commands[i]);
        Serial.printf("%i, ",commands[i]);
    }
    int status = Wire.endTransmission();
    Serial.printf(" Status: %i \n", status);
    return status;
};
int bytesToInt(byte bytes[], int length){
    int ret = bytes[0];
    for(int i=1; i<length; i++){
        ret = ret << 8;
        ret += bytes[i];
    }
    return ret;
}
<|endoftext|>


<commit_before>#include <ros.h>
#include <string.h>

#include "std_msgs/String.h"
#include "maelstrom_msgs/PwmRequests.h"
#include "maelstrom_msgs/ThrusterForces.h"
#include "maelstrom_msgs/LightInput.h"

#include "ForceToPwmLookup.h"

//incleder for IMU og trykksensor
#include "MPU6050/MPU6050.h"
#include "MS5803_14BA.h"
#include <Wire.h>
#include <geometry_msgs/Vector3.h>
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/MagneticField.h"
#include "sensor_msgs/Temperature.h"
#include "sensor_msgs/FluidPressure.h"

#define STANDARD_GRAVITY 9.08665  // [m/s^2]
#define RAD_PER_DEG 0.01745329252 // [1/deg]
#define PASCAL_PER_MILLIBAR 0.01  // [Pa/mbar]

#define MPU9150_I2C_ADDR 0x69
MPU6050 accelgyro(MPU9150_I2C_ADDR);

MS5803_14BA depthSensor;

ros::NodeHandle nh;

sensor_msgs::Imu imu_raw_msg;
sensor_msgs::MagneticField compass_msg;
sensor_msgs::Temperature temperature_msg;
sensor_msgs::FluidPressure pressure_msg;

ros::Publisher pub_imu("imu/data_raw", &imu_raw_msg);
ros::Publisher pub_pressure("imu/pressure", &pressure_msg);

const int SensorReadDelay = 83;
unsigned long PrevoiusSensorReadMillis = 0;

int dbg_count = 0;

//Hold orden på pwm-pins til motor og lys
const int PwmCount = 7;
const int PwmPins[PwmCount] = { 7, 8, 12, 13, 44, 45,      10};
const int LigthPwmPin = PwmPins[PwmCount-1]; //pin 10 er på Timer / Counter 2
int PwmValue[PwmCount];

//Sett opp topics til debugmeldinger
maelstrom_msgs::PwmRequests  pwm_status_msg;
std_msgs::String arduino_dbg_msg;

ros::Publisher pwm_status_pub("pwm_status", &pwm_status_msg);
ros::Publisher arduino_dbg_pub("arduino_dbg", &arduino_dbg_msg);

void WritePwm(int pin, uint8_t value) {
  switch(pin) {
    //LYS
  case 10:
    analogWrite(pin, value);
    break;

    //MOTOR
  case 7:
    OCR4BH = 0;
    OCR4BL = value;
    break;
  case 8:
    OCR4CH = 0;
    OCR4CL = value;
    break;
  case 12:
    OCR1BH = 0;
    OCR1BL = value;
    break;
  case 13:
    OCR1CH = 0;
    OCR1CL = value;
    break;
  case 44:
    OCR5BH = 0;
    OCR5BL = value;
    break;
  case 45:
    OCR5CH = 0;
    OCR5CL = value;
    break;
  };
}

void InitPwm() {

  //sett alle pwmpinnene som utputt
  for(int i = 0; i < PwmCount; i++)
    pinMode(PwmPins[i], OUTPUT);

  //initialiser Timer/Counter 3, 4 og 5
  TCCR1A |= (1<<COM1B1) | (1<<COM1C1)  | (1<<WGM11) | (1<<WGM10);
  TCCR4A |= (1<<COM4B1) | (1<<COM4C1)  | (1<<WGM41) | (1<<WGM40);
  TCCR5A |= (1<<COM5B1) | (1<<COM5C1)  | (1<<WGM51) | (1<<WGM50);

  //sett Clock select
  //på Timer/Counter 1
  TCCR1B |= (1<<CS11) | (1<<CS10);
  TCCR1B &= ~(1<<CS12);
  //På Timer/Counter 4
  TCCR4B |= (1<<CS41) | (1<<CS40);
  TCCR4B &= ~(1<<CS42);
  //på Timer/Counter 5
  TCCR5B |= (1<<CS51) | (1<<CS50);
  TCCR5B &= ~(1<<CS52);

  //sett alle motorer til 0 Newton
  for(int i = 0; i < PwmCount; i++) {
    PwmValue[i] = ForceToPwm(0);
    WritePwm(PwmPins[i], PwmValue[i]);
  }
  //og så av lys
  PwmValue[LigthPwmPin] = 0;
  WritePwm(LigthPwmPin, 0);

}

void publishPwmStatus() {
  //Send PWM-verdiene tilbake som debugoutput
  pwm_status_msg.pwm1 = PwmValue[0];
  pwm_status_msg.pwm2 = PwmValue[1];
  pwm_status_msg.pwm3 = PwmValue[2];
  pwm_status_msg.pwm4 = PwmValue[3];
  pwm_status_msg.pwm5 = PwmValue[4];
  pwm_status_msg.pwm6 = PwmValue[5];
  pwm_status_msg.pwm7 = PwmValue[6];

  pwm_status_pub.publish( &pwm_status_msg );
}

void pwm_update( const maelstrom_msgs::ThrusterForces& force_input ){

  PwmValue[0] = ForceToPwm(force_input.F1);
  PwmValue[1] = ForceToPwm(force_input.F2);
  PwmValue[2] = ForceToPwm(force_input.F3);
  PwmValue[3] = ForceToPwm(force_input.F4);
  PwmValue[4] = ForceToPwm(force_input.F5);
  PwmValue[5] = ForceToPwm(force_input.F6);

  for(int i = 0; i < PwmCount; i++) {
    WritePwm(PwmPins[i], PwmValue[i]);
  }

  dbg_count = 0;

  publishPwmStatus();
}

ros::Subscriber<maelstrom_msgs::ThrusterForces> pwm_input_sub("thruster_forces", &pwm_update );

void LightPwmUpdate( const maelstrom_msgs::LightInput &light_msg) {
  PwmValue[6] = light_msg.light_intensity;

  WritePwm(LigthPwmPin, PwmValue[6]);

  publishPwmStatus();
}

ros::Subscriber<maelstrom_msgs::LightInput> light_pwm_input_sub("LightPwm", &LightPwmUpdate );

double GyroLsbSens, AccelLsbSens;
void getFsRangeAndSetLsbSensisivity() {

  uint8_t GyroFsRange, AccelFsRange;

  GyroFsRange = accelgyro.getFullScaleGyroRange();
  /* Gyro
   * FS_SEL | Full Scale Range   | LSB Sensitivity
   * -------+--------------------+----------------
   * 0      | +/- 250 degrees/s  | 131 LSB/deg/s
   * 1      | +/- 500 degrees/s  | 65.5 LSB/deg/s
   * 2      | +/- 1000 degrees/s | 32.8 LSB/deg/s
   * 3      | +/- 2000 degrees/s | 16.4 LSB/deg/s
   */
  switch(GyroFsRange) {
  case 0:
    GyroLsbSens = 131.0;
    break;
  case 1:
    GyroLsbSens = 65.5;
    break;
  case 2:
    GyroLsbSens = 32.8;
    break;
  case 3:
    GyroLsbSens = 16.4;
    break;
  };

  AccelFsRange = accelgyro.getFullScaleAccelRange();
  /*Accelerometer
   * AFS_SEL | Full Scale Range | LSB Sensitivity
   * --------+------------------+----------------
   * 0       | +/- 2g           | 16384 LSB/g
   * 1       | +/- 4g           | 8192 LSB/g
   * 2       | +/- 8g           | 4096 LSB/g
   * 3       | +/- 16g          | 2048 LSB/g
   */
  switch(AccelFsRange) {
  case 0:
    AccelLsbSens = 16384.0;
    break;
  case 1:
    AccelLsbSens = 8192.0;
    break;
  case 2:
    AccelLsbSens = 4096.0;
    break;
  case 3:
    AccelLsbSens = 2048.0;
    break;
  };

}

void setup() {

  InitPwm();

  //start ROS-node
  nh.initNode();

  nh.advertise(pwm_status_pub);
  nh.advertise(arduino_dbg_pub);

  nh.advertise(pub_imu);
  nh.subscribe(pwm_input_sub);
  nh.subscribe(light_pwm_input_sub);
  nh.spinOnce();

  // Initialize the 'Wire' class for the I2C-bus.
  // I2C pins: 20 (SDA) og 21 (SCL) (Mega2560)
  Wire.begin();
  accelgyro.initialize();
  getFsRangeAndSetLsbSensisivity();

  depthSensor.initialize(false);

  nh.spinOnce();
  String dbg_msg =  String("init:\n") +
    (accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  arduino_dbg_msg.data = dbg_msg.c_str();
  arduino_dbg_pub.publish( &arduino_dbg_msg );

  nh.spinOnce();

}

void lesSensorer() {

  int16_t ax, ay, az;
  int16_t gx, gy, gz;
  int16_t mx, my, mz;

  accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

  //Accelerometerdata enhet: [m/s^2]
  imu_raw_msg.linear_acceleration.x = (ax * STANDARD_GRAVITY) / AccelLsbSens; // OBS! MÅ VÆRE m/s^2!
  imu_raw_msg.linear_acceleration.y = (ay * STANDARD_GRAVITY) / AccelLsbSens; // OBS! MÅ VÆRE m/s^2!
  imu_raw_msg.linear_acceleration.z = (az * STANDARD_GRAVITY) / AccelLsbSens; // OBS! MÅ VÆRE m/s^2!

  //Gyrodata: enhet [rad/s]
  imu_raw_msg.angular_velocity.x = (gx * RAD_PER_DEG) / GyroLsbSens; // OBS! MÅ VÆRE RAD/SEC
  imu_raw_msg.angular_velocity.y = (gy * RAD_PER_DEG) / GyroLsbSens; // OBS! MÅ VÆRE RAD/SEC
  imu_raw_msg.angular_velocity.z = (gz * RAD_PER_DEG) / GyroLsbSens; // OBS! MÅ VÆRE RAD/SEC

  // Kompass, enhet [T]
  // TODO finn ut om 0.3 er riktig skaleringsfaktor
  compass_msg.magnetic_field.x = mx * 0.3; // OBS! MÅ VÆRE TESLA! (IKKE MILLI/MICRO)
  compass_msg.magnetic_field.y = my * 0.3; // OBS! MÅ VÆRE TESLA! (IKKE MILLI/MICRO)
  compass_msg.magnetic_field.z = mz * 0.3; // OBS! MÅ VÆRE TESLA! (IKKE MILLI/MICRO)

  temperature_msg.temperature = ( (double)accelgyro.getTemperature() + 12412.0) / 340.0;

  depthSensor.read();
  pressure_msg.fluid_pressure = depthSensor.getPreassure() * PASCAL_PER_MILLIBAR; // OBS! MÅ VÆRE I PASCAL
}

void loop(){

  nh.spinOnce();

  if( millis() - PrevoiusSensorReadMillis >= SensorReadDelay ) {
    PrevoiusSensorReadMillis = millis();

    lesSensorer();
    //nh.spinOnce();
    pub_imu.publish(&imu_raw_msg);
    pub_pressure.publish(&pressure_msg);
  }

  /*
  //String dbg_msg = "pwm updated after " + String(dbg_count) + " cycles";
  //String dbg_msg = "accelX = " ;//+ String(imu.read(MPU9150_ACCEL_XOUT_L, MPU9150_ACCEL_XOUT_H));
  String dbg_msg = String("GyroFsRange = ") + String(GyroFsRange) +
  String("\nAccelFsRange = ") + String(AccelFsRange);
  arduino_dbg_msg.data = dbg_msg.c_str();
  arduino_dbg_pub.publish( &arduino_dbg_msg );
  nh.spinOnce();
  */

}
<commit_msg>stillt inn lavpassfilter<commit_after>#include <ros.h>
#include <string.h>

#include "std_msgs/String.h"
#include "maelstrom_msgs/PwmRequests.h"
#include "maelstrom_msgs/ThrusterForces.h"
#include "maelstrom_msgs/LightInput.h"

#include "ForceToPwmLookup.h"

//incleder for IMU og trykksensor
#include "MPU6050/MPU6050.h"
#include "MS5803_14BA.h"
#include <Wire.h>
#include <geometry_msgs/Vector3.h>
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/MagneticField.h"
#include "sensor_msgs/Temperature.h"
#include "sensor_msgs/FluidPressure.h"

#define STANDARD_GRAVITY 9.08665  // [m/s^2]
#define RAD_PER_DEG 0.01745329252 // [1/deg]
#define PASCAL_PER_MILLIBAR 0.01  // [Pa/mbar]

#define MPU9150_I2C_ADDR 0x69
MPU6050 accelgyro(MPU9150_I2C_ADDR);

MS5803_14BA depthSensor;

ros::NodeHandle nh;

sensor_msgs::Imu imu_raw_msg;
sensor_msgs::MagneticField compass_msg;
sensor_msgs::Temperature temperature_msg;
sensor_msgs::FluidPressure pressure_msg;

ros::Publisher pub_imu("imu/data_raw", &imu_raw_msg);
ros::Publisher pub_pressure("imu/pressure", &pressure_msg);

const int SensorReadDelay = 83;
unsigned long PrevoiusSensorReadMillis = 0;

int dbg_count = 0;

//Hold orden på pwm-pins til motor og lys
const int PwmCount = 7;
const int PwmPins[PwmCount] = { 7, 8, 12, 13, 44, 45,      10};
const int LigthPwmPin = PwmPins[PwmCount-1]; //pin 10 er på Timer / Counter 2
int PwmValue[PwmCount];

//Sett opp topics til debugmeldinger
maelstrom_msgs::PwmRequests  pwm_status_msg;
std_msgs::String arduino_dbg_msg;

ros::Publisher pwm_status_pub("pwm_status", &pwm_status_msg);
ros::Publisher arduino_dbg_pub("arduino_dbg", &arduino_dbg_msg);

void WritePwm(int pin, uint8_t value) {
  switch(pin) {
    //LYS
  case 10:
    analogWrite(pin, value);
    break;

    //MOTOR
  case 7:
    OCR4BH = 0;
    OCR4BL = value;
    break;
  case 8:
    OCR4CH = 0;
    OCR4CL = value;
    break;
  case 12:
    OCR1BH = 0;
    OCR1BL = value;
    break;
  case 13:
    OCR1CH = 0;
    OCR1CL = value;
    break;
  case 44:
    OCR5BH = 0;
    OCR5BL = value;
    break;
  case 45:
    OCR5CH = 0;
    OCR5CL = value;
    break;
  };
}

void InitPwm() {

  //sett alle pwmpinnene som utputt
  for(int i = 0; i < PwmCount; i++)
    pinMode(PwmPins[i], OUTPUT);

  //initialiser Timer/Counter 3, 4 og 5
  TCCR1A |= (1<<COM1B1) | (1<<COM1C1)  | (1<<WGM11) | (1<<WGM10);
  TCCR4A |= (1<<COM4B1) | (1<<COM4C1)  | (1<<WGM41) | (1<<WGM40);
  TCCR5A |= (1<<COM5B1) | (1<<COM5C1)  | (1<<WGM51) | (1<<WGM50);

  //sett Clock select
  //på Timer/Counter 1
  TCCR1B |= (1<<CS11) | (1<<CS10);
  TCCR1B &= ~(1<<CS12);
  //På Timer/Counter 4
  TCCR4B |= (1<<CS41) | (1<<CS40);
  TCCR4B &= ~(1<<CS42);
  //på Timer/Counter 5
  TCCR5B |= (1<<CS51) | (1<<CS50);
  TCCR5B &= ~(1<<CS52);

  //sett alle motorer til 0 Newton
  for(int i = 0; i < PwmCount; i++) {
    PwmValue[i] = ForceToPwm(0);
    WritePwm(PwmPins[i], PwmValue[i]);
  }
  //og så av lys
  PwmValue[LigthPwmPin] = 0;
  WritePwm(LigthPwmPin, 0);

}

void publishPwmStatus() {
  //Send PWM-verdiene tilbake som debugoutput
  pwm_status_msg.pwm1 = PwmValue[0];
  pwm_status_msg.pwm2 = PwmValue[1];
  pwm_status_msg.pwm3 = PwmValue[2];
  pwm_status_msg.pwm4 = PwmValue[3];
  pwm_status_msg.pwm5 = PwmValue[4];
  pwm_status_msg.pwm6 = PwmValue[5];
  pwm_status_msg.pwm7 = PwmValue[6];

  pwm_status_pub.publish( &pwm_status_msg );
}

void pwm_update( const maelstrom_msgs::ThrusterForces& force_input ){

  PwmValue[0] = ForceToPwm(force_input.F1);
  PwmValue[1] = ForceToPwm(force_input.F2);
  PwmValue[2] = ForceToPwm(force_input.F3);
  PwmValue[3] = ForceToPwm(force_input.F4);
  PwmValue[4] = ForceToPwm(force_input.F5);
  PwmValue[5] = ForceToPwm(force_input.F6);

  for(int i = 0; i < PwmCount; i++) {
    WritePwm(PwmPins[i], PwmValue[i]);
  }

  dbg_count = 0;

  publishPwmStatus();
}

void LightPwmUpdate( const maelstrom_msgs::LightInput &light_msg) {
  PwmValue[6] = light_msg.light_intensity;

  WritePwm(LigthPwmPin, PwmValue[6]);

  publishPwmStatus();
}

ros::Subscriber<maelstrom_msgs::ThrusterForces> pwm_input_sub("thruster_forces", &pwm_update );
ros::Subscriber<maelstrom_msgs::LightInput> light_pwm_input_sub("LightPwm", &LightPwmUpdate );

double GyroLsbSens, AccelLsbSens;
void getFsRangeAndSetLsbSensisivity() {

  uint8_t GyroFsRange, AccelFsRange;

  GyroFsRange = accelgyro.getFullScaleGyroRange();
  /* Gyro
   * FS_SEL | Full Scale Range   | LSB Sensitivity
   * -------+--------------------+----------------
   * 0      | +/- 250 degrees/s  | 131 LSB/deg/s
   * 1      | +/- 500 degrees/s  | 65.5 LSB/deg/s
   * 2      | +/- 1000 degrees/s | 32.8 LSB/deg/s
   * 3      | +/- 2000 degrees/s | 16.4 LSB/deg/s
   */
  switch(GyroFsRange) {
  case 0:
    GyroLsbSens = 131.0;
    break;
  case 1:
    GyroLsbSens = 65.5;
    break;
  case 2:
    GyroLsbSens = 32.8;
    break;
  case 3:
    GyroLsbSens = 16.4;
    break;
  };

  AccelFsRange = accelgyro.getFullScaleAccelRange();
  /*Accelerometer
   * AFS_SEL | Full Scale Range | LSB Sensitivity
   * --------+------------------+----------------
   * 0       | +/- 2g           | 16384 LSB/g
   * 1       | +/- 4g           | 8192 LSB/g
   * 2       | +/- 8g           | 4096 LSB/g
   * 3       | +/- 16g          | 2048 LSB/g
   */
  switch(AccelFsRange) {
  case 0:
    AccelLsbSens = 16384.0;
    break;
  case 1:
    AccelLsbSens = 8192.0;
    break;
  case 2:
    AccelLsbSens = 4096.0;
    break;
  case 3:
    AccelLsbSens = 2048.0;
    break;
  };

}

void setup() {

  InitPwm();

  //start ROS-node
  nh.initNode();

  nh.advertise(pwm_status_pub);
  nh.advertise(arduino_dbg_pub);

  nh.advertise(pub_imu);
  nh.subscribe(pwm_input_sub);
  nh.subscribe(light_pwm_input_sub);
  nh.spinOnce();

  // Initialize the 'Wire' class for the I2C-bus.
  // I2C pins: 20 (SDA) og 21 (SCL) (Mega2560)
  Wire.begin();
  accelgyro.initialize();
  getFsRangeAndSetLsbSensisivity();
  //Sett lavpassfilter se http://www.i2cdevlib.com/docs/html/class_m_p_u6050.html#a9f2737fe22955fd85b2575ba8da874c6
  accelgyro.setDHPFMode(3); //acc 44Hz 4.9ms, gyro 42Hz 4.8ms

  depthSensor.initialize(false);

  nh.spinOnce();
  String dbg_msg =  String("init:\n") +
    (accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  arduino_dbg_msg.data = dbg_msg.c_str();
  arduino_dbg_pub.publish( &arduino_dbg_msg );

  nh.spinOnce();

}

void lesSensorer() {

  int16_t ax, ay, az;
  int16_t gx, gy, gz;
  int16_t mx, my, mz;

  accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

  //Accelerometerdata enhet: [m/s^2]
  imu_raw_msg.linear_acceleration.x = (ax * STANDARD_GRAVITY) / AccelLsbSens; // OBS! MÅ VÆRE m/s^2!
  imu_raw_msg.linear_acceleration.y = (ay * STANDARD_GRAVITY) / AccelLsbSens; // OBS! MÅ VÆRE m/s^2!
  imu_raw_msg.linear_acceleration.z = (az * STANDARD_GRAVITY) / AccelLsbSens; // OBS! MÅ VÆRE m/s^2!

  //Gyrodata: enhet [rad/s]
  imu_raw_msg.angular_velocity.x = (gx * RAD_PER_DEG) / GyroLsbSens; // OBS! MÅ VÆRE RAD/SEC
  imu_raw_msg.angular_velocity.y = (gy * RAD_PER_DEG) / GyroLsbSens; // OBS! MÅ VÆRE RAD/SEC
  imu_raw_msg.angular_velocity.z = (gz * RAD_PER_DEG) / GyroLsbSens; // OBS! MÅ VÆRE RAD/SEC

  // Kompass, enhet [T]
  // TODO finn ut om 0.3 er riktig skaleringsfaktor
  compass_msg.magnetic_field.x = mx * 0.3; // OBS! MÅ VÆRE TESLA! (IKKE MILLI/MICRO)
  compass_msg.magnetic_field.y = my * 0.3; // OBS! MÅ VÆRE TESLA! (IKKE MILLI/MICRO)
  compass_msg.magnetic_field.z = mz * 0.3; // OBS! MÅ VÆRE TESLA! (IKKE MILLI/MICRO)

  temperature_msg.temperature = ( (double)accelgyro.getTemperature() + 12412.0) / 340.0;

  depthSensor.read();
  pressure_msg.fluid_pressure = depthSensor.getPreassure() * PASCAL_PER_MILLIBAR; // OBS! MÅ VÆRE I PASCAL
}

void loop(){

  nh.spinOnce();

  if( millis() - PrevoiusSensorReadMillis >= SensorReadDelay ) {
    PrevoiusSensorReadMillis = millis();

    lesSensorer();
    //nh.spinOnce();
    pub_imu.publish(&imu_raw_msg);
    pub_pressure.publish(&pressure_msg);
  }

  /*
  //String dbg_msg = "pwm updated after " + String(dbg_count) + " cycles";
  //String dbg_msg = "accelX = " ;//+ String(imu.read(MPU9150_ACCEL_XOUT_L, MPU9150_ACCEL_XOUT_H));
  String dbg_msg = String("GyroFsRange = ") + String(GyroFsRange) +
  String("\nAccelFsRange = ") + String(AccelFsRange);
  arduino_dbg_msg.data = dbg_msg.c_str();
  arduino_dbg_pub.publish( &arduino_dbg_msg );
  nh.spinOnce();
  */

}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#define MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>
#include <mjolnir/omp/sort.hpp>
#include <mjolnir/core/UnlimitedGridCellList.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT, typename potentialT>
class UnlimitedGridCellList<OpenMPSimulatorTraits<realT, boundaryT>, potentialT>
    final : public SpatialPartitionBase<OpenMPSimulatorTraits<realT, boundaryT>, potentialT>
{
  public:
    using traits_type        = OpenMPSimulatorTraits<realT, boundaryT>;
    using potential_type     = potentialT;
    using base_type          = SpatialPartitionBase<traits_type, potential_type>;

    using system_type        = typename base_type::system_type;
    using boundary_type      = typename base_type::boundary_type;
    using real_type          = typename base_type::real_type;
    using coordinate_type    = typename base_type::coordinate_type;
    using neighbor_list_type = typename base_type::neighbor_list_type;
    using neighbor_type      = typename base_type::neighbor_type;
    using range_type         = typename base_type::range_type;

    static constexpr std::size_t  dim_size () {return 8;}
    static constexpr std::int64_t dim      () {return 8;}
    static constexpr real_type mesh_epsilon() {return 1e-6;}

    using particle_cell_idx_pair    = std::pair<std::size_t, std::size_t>;
    using cell_index_container_type = std::vector<particle_cell_idx_pair>;
    using cell_index_const_iterator = typename cell_index_container_type::const_iterator;
    using adjacent_cell_idx         = std::array<std::size_t, 27>;
    using cell_type                 = std::pair<range<cell_index_const_iterator>, adjacent_cell_idx>;
    using cell_list_type            = std::array<cell_type, dim_size() * dim_size() * dim_size()>;

  public:

    UnlimitedGridCellList()
        : margin_(0.5), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    ~UnlimitedGridCellList() = default;
    UnlimitedGridCellList(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList(UnlimitedGridCellList &&)     = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList &&)     = default;

    explicit UnlimitedGridCellList(const real_type margin)
        : margin_(margin), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    bool valid() const noexcept override
    {
        return current_margin_ >= 0.;
    }

    //XXX do NOT call this from parallel region.
    void initialize(neighbor_list_type& neighbors,
                    const system_type& sys, const potential_type& pot) override
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        constexpr std::int64_t d = dim();

        MJOLNIR_LOG_INFO(pot.name(), " cutoff = ", pot.max_cutoff_length());
        MJOLNIR_LOG_INFO("dimension = ", d, 'x', d, 'x', d);
        this->set_cutoff(pot.max_cutoff_length());

        // initialize cell list
#pragma omp parallel for
        for(int x = 0; x < d; ++x)
        {
            for(int y = 0; y < d; ++y)
            {
            for(int z = 0; z < d; ++z)
            {
                auto& cell = this->cell_list_[calc_index(x, y, z)];

                const std::size_t x_prev = (x ==   0) ? d-1 : x-1;
                const std::size_t x_next = (x == d-1) ?   0 : x+1;
                const std::size_t y_prev = (y ==   0) ? d-1 : y-1;
                const std::size_t y_next = (y == d-1) ?   0 : y+1;
                const std::size_t z_prev = (z ==   0) ? d-1 : z-1;
                const std::size_t z_next = (z == d-1) ?   0 : z+1;

                cell.second[ 0] = calc_index(x_prev, y_prev, z_prev);
                cell.second[ 1] = calc_index(x,      y_prev, z_prev);
                cell.second[ 2] = calc_index(x_next, y_prev, z_prev);
                cell.second[ 3] = calc_index(x_prev, y,      z_prev);
                cell.second[ 4] = calc_index(x,      y,      z_prev);
                cell.second[ 5] = calc_index(x_next, y,      z_prev);
                cell.second[ 6] = calc_index(x_prev, y_next, z_prev);
                cell.second[ 7] = calc_index(x,      y_next, z_prev);
                cell.second[ 8] = calc_index(x_next, y_next, z_prev);

                cell.second[ 9] = calc_index(x_prev, y_prev, z);
                cell.second[10] = calc_index(x,      y_prev, z);
                cell.second[11] = calc_index(x_next, y_prev, z);
                cell.second[12] = calc_index(x_prev, y,      z);
                cell.second[13] = calc_index(x,      y,      z);
                cell.second[14] = calc_index(x_next, y,      z);
                cell.second[15] = calc_index(x_prev, y_next, z);
                cell.second[16] = calc_index(x,      y_next, z);
                cell.second[17] = calc_index(x_next, y_next, z);

                cell.second[18] = calc_index(x_prev, y_prev, z_next);
                cell.second[19] = calc_index(x,      y_prev, z_next);
                cell.second[20] = calc_index(x_next, y_prev, z_next);
                cell.second[21] = calc_index(x_prev, y,      z_next);
                cell.second[22] = calc_index(x,      y,      z_next);
                cell.second[23] = calc_index(x_next, y,      z_next);
                cell.second[24] = calc_index(x_prev, y_next, z_next);
                cell.second[25] = calc_index(x,      y_next, z_next);
                cell.second[26] = calc_index(x_next, y_next, z_next);
            } // for z
            } // for y
        } // for x (in parallel)

        this->make(neighbors, sys, pot);
        return;
    }

    //XXX do NOT call this from parallel region
    void make(neighbor_list_type& neighbors,
              const system_type& sys, const potential_type& pot) override
    {
        // `participants` is a list that contains indices of particles that are
        // related to the potential.
        const auto& participants = pot.participants();

        neighbors.clear();
        if(index_by_cell_    .size() != sys.size() ||
           index_by_cell_buf_.size() != sys.size())
        {
            index_by_cell_    .resize(sys.size());
            index_by_cell_buf_.resize(sys.size());
        }

#pragma omp parallel for
        for(std::size_t i=0; i<participants.size(); ++i)
        {
            const auto idx = participants[i];
            index_by_cell_[i] =
                std::make_pair(idx, this->calc_index(sys.position(idx)));
        }

        omp::sort(this->index_by_cell_, this->index_by_cell_buf_,
                  [](const particle_cell_idx_pair& lhs,
                     const particle_cell_idx_pair& rhs) noexcept -> bool {
                      return lhs.second < rhs.second;
                  });

        // assign first and last iterator for each cells
#pragma omp parallel for
        for(std::size_t cell_idx=0; cell_idx<cell_list_.size(); ++cell_idx)
        {
            auto iter = std::find_if(index_by_cell_.cbegin(), index_by_cell_.cend(),
                [cell_idx](const particle_cell_idx_pair& item) noexcept -> bool {
                    return item.second == cell_idx;
                });
            if(iter == index_by_cell_.cend())
            {
                cell_list_[cell_idx].first = make_range(iter, iter);
                continue;
            }
            const auto first = iter; // the first iter of the range
            while(iter != index_by_cell_.cend() && iter->second == cell_idx)
            {
                ++iter;
            }
            cell_list_[cell_idx].first = make_range(first, iter);
        }

        const real_type r_c  = cutoff_ * (1 + margin_);
        const real_type r_c2 = r_c * r_c;

//XXX ParallelNeighborList consumes quite a lot of memory resources and makes
//XXX both construction and access slower (especially when system has a small
//XXX number of particles). Because of this, after some benchmarking, I found
//XXX that normal NeighborList works good for most of the cases. Some part of
//XXX neighbor-list construction cannot be parallelized, but it becomes still
//XXX faster.

        std::vector<neighbor_type> partner;
        for(std::size_t idx=0; idx<participants.size(); ++idx)
        {
            partner.clear();
            const auto  i    = participants[idx];
            const auto& ri   = sys.position(i);
            const auto& cell = cell_list_[this->calc_index(ri)];

            MJOLNIR_LOG_DEBUG("particle position ", sys.position(i));
            MJOLNIR_LOG_DEBUG("cell index ",        calc_index(ri));
            MJOLNIR_LOG_DEBUG("making verlet list for index ", i);

            for(std::size_t cidx : cell.second) // for all adjacent cells...
            {
                MJOLNIR_LOG_DEBUG("neighbor cell index ", cidx);
                for(auto pici : cell_list_[cidx].first)
                {
                    const auto j = pici.first;
                    MJOLNIR_LOG_DEBUG("looking particle ", j);
                    if(j <= i || !pot.has_interaction(i, j))
                    {
                        continue;
                    }
                    // here we don't need to search `participants` because
                    // cell list contains only participants. non-related
                    // particles are already filtered.

                    const auto& rj = sys.position(j);
                    if(math::length_sq(sys.adjust_direction(rj - ri)) < r_c2)
                    {
                        MJOLNIR_LOG_DEBUG("add index ", j, " to list ", i);
                        partner.emplace_back(j, pot.prepare_params(i, j));
                    }
                }
            }
            // make the result consistent with NaivePairCalculation...
            std::sort(partner.begin(), partner.end());
            neighbors.add_list_for(i, partner.begin(), partner.end());
        }

        this->current_margin_ = cutoff_ * margin_;
        return ;
    }

    //XXX do NOT call this from `parallel` region.
    void update(neighbor_list_type& neighbors, const real_type dmargin,
                const system_type& sys, const potential_type& pot) override
    {
        this->current_margin_ -= dmargin;

        if(this->current_margin_ < 0.)
        {
            this->make(neighbors, sys, pot);
        }
        return ;
    }

    real_type cutoff() const noexcept override {return this->cutoff_;}
    real_type margin() const noexcept override {return this->margin_;}

  private:

    // calc cell index of the position
    std::size_t calc_index(const coordinate_type& pos) const noexcept
    {
        constexpr std::int64_t d = dim();
        const auto x = std::int64_t(std::floor(math::X(pos) * r_cell_size_)) % d;
        const auto y = std::int64_t(std::floor(math::Y(pos) * r_cell_size_)) % d;
        const auto z = std::int64_t(std::floor(math::Z(pos) * r_cell_size_)) % d;

        return this->calc_index((x<0) ? x+d : x, (y<0) ? y+d : y, (z<0) ? z+d : z);
    }

    std::size_t calc_index(const std::size_t x, const std::size_t y,
                           const std::size_t z) const noexcept
    {
        return x + dim_size() * y + dim_size() * dim_size() * z;
    }

    void set_cutoff(const real_type c) noexcept
    {
        this->cutoff_ = c;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon()));
    }
    void set_margin(const real_type m) noexcept
    {
        this->margin_ = m;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon()));
    }

  private:

    real_type cutoff_;
    real_type margin_;
    real_type current_margin_;
    real_type r_cell_size_;

    neighbor_list_type        neighbors_;
    cell_list_type            cell_list_;
    cell_index_container_type index_by_cell_;
    cell_index_container_type index_by_cell_buf_; // buffer for sort
    // index_by_cell_ has {particle idx, cell idx} and sorted by cell idx
    // first term of cell list contains first and last idx of index_by_cell
};
} // mjolnir

#ifdef MJOLNIR_SEPARATE_BUILD
#include <mjolnir/potential/global/DebyeHuckelPotential.hpp>
#include <mjolnir/potential/global/ExcludedVolumePotential.hpp>
#include <mjolnir/potential/global/LennardJonesPotential.hpp>
#include <mjolnir/potential/global/UniformLennardJonesPotential.hpp>

namespace mjolnir
{
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, DebyeHuckelPotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, DebyeHuckelPotential<float >>;

extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, ExcludedVolumePotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, ExcludedVolumePotential<float >>;

extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, LennardJonesPotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, LennardJonesPotential<float >>;

extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, UniformLennardJonesPotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, UniformLennardJonesPotential<float >>;
}
#endif // MJOLNIR_SEPARATE_BUILD
#endif/* MJOLNIR_UNLIMITED_GRID_CELL_LIST */
<commit_msg>fix: lack of logger declaration in debug mode<commit_after>#ifndef MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#define MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>
#include <mjolnir/omp/sort.hpp>
#include <mjolnir/core/UnlimitedGridCellList.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT, typename potentialT>
class UnlimitedGridCellList<OpenMPSimulatorTraits<realT, boundaryT>, potentialT>
    final : public SpatialPartitionBase<OpenMPSimulatorTraits<realT, boundaryT>, potentialT>
{
  public:
    using traits_type        = OpenMPSimulatorTraits<realT, boundaryT>;
    using potential_type     = potentialT;
    using base_type          = SpatialPartitionBase<traits_type, potential_type>;

    using system_type        = typename base_type::system_type;
    using boundary_type      = typename base_type::boundary_type;
    using real_type          = typename base_type::real_type;
    using coordinate_type    = typename base_type::coordinate_type;
    using neighbor_list_type = typename base_type::neighbor_list_type;
    using neighbor_type      = typename base_type::neighbor_type;
    using range_type         = typename base_type::range_type;

    static constexpr std::size_t  dim_size () {return 8;}
    static constexpr std::int64_t dim      () {return 8;}
    static constexpr real_type mesh_epsilon() {return 1e-6;}

    using particle_cell_idx_pair    = std::pair<std::size_t, std::size_t>;
    using cell_index_container_type = std::vector<particle_cell_idx_pair>;
    using cell_index_const_iterator = typename cell_index_container_type::const_iterator;
    using adjacent_cell_idx         = std::array<std::size_t, 27>;
    using cell_type                 = std::pair<range<cell_index_const_iterator>, adjacent_cell_idx>;
    using cell_list_type            = std::array<cell_type, dim_size() * dim_size() * dim_size()>;

  public:

    UnlimitedGridCellList()
        : margin_(0.5), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    ~UnlimitedGridCellList() = default;
    UnlimitedGridCellList(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList(UnlimitedGridCellList &&)     = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList &&)     = default;

    explicit UnlimitedGridCellList(const real_type margin)
        : margin_(margin), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    bool valid() const noexcept override
    {
        return current_margin_ >= 0.;
    }

    //XXX do NOT call this from parallel region.
    void initialize(neighbor_list_type& neighbors,
                    const system_type& sys, const potential_type& pot) override
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        constexpr std::int64_t d = dim();

        MJOLNIR_LOG_INFO(pot.name(), " cutoff = ", pot.max_cutoff_length());
        MJOLNIR_LOG_INFO("dimension = ", d, 'x', d, 'x', d);
        this->set_cutoff(pot.max_cutoff_length());

        // initialize cell list
#pragma omp parallel for
        for(int x = 0; x < d; ++x)
        {
            for(int y = 0; y < d; ++y)
            {
            for(int z = 0; z < d; ++z)
            {
                auto& cell = this->cell_list_[calc_index(x, y, z)];

                const std::size_t x_prev = (x ==   0) ? d-1 : x-1;
                const std::size_t x_next = (x == d-1) ?   0 : x+1;
                const std::size_t y_prev = (y ==   0) ? d-1 : y-1;
                const std::size_t y_next = (y == d-1) ?   0 : y+1;
                const std::size_t z_prev = (z ==   0) ? d-1 : z-1;
                const std::size_t z_next = (z == d-1) ?   0 : z+1;

                cell.second[ 0] = calc_index(x_prev, y_prev, z_prev);
                cell.second[ 1] = calc_index(x,      y_prev, z_prev);
                cell.second[ 2] = calc_index(x_next, y_prev, z_prev);
                cell.second[ 3] = calc_index(x_prev, y,      z_prev);
                cell.second[ 4] = calc_index(x,      y,      z_prev);
                cell.second[ 5] = calc_index(x_next, y,      z_prev);
                cell.second[ 6] = calc_index(x_prev, y_next, z_prev);
                cell.second[ 7] = calc_index(x,      y_next, z_prev);
                cell.second[ 8] = calc_index(x_next, y_next, z_prev);

                cell.second[ 9] = calc_index(x_prev, y_prev, z);
                cell.second[10] = calc_index(x,      y_prev, z);
                cell.second[11] = calc_index(x_next, y_prev, z);
                cell.second[12] = calc_index(x_prev, y,      z);
                cell.second[13] = calc_index(x,      y,      z);
                cell.second[14] = calc_index(x_next, y,      z);
                cell.second[15] = calc_index(x_prev, y_next, z);
                cell.second[16] = calc_index(x,      y_next, z);
                cell.second[17] = calc_index(x_next, y_next, z);

                cell.second[18] = calc_index(x_prev, y_prev, z_next);
                cell.second[19] = calc_index(x,      y_prev, z_next);
                cell.second[20] = calc_index(x_next, y_prev, z_next);
                cell.second[21] = calc_index(x_prev, y,      z_next);
                cell.second[22] = calc_index(x,      y,      z_next);
                cell.second[23] = calc_index(x_next, y,      z_next);
                cell.second[24] = calc_index(x_prev, y_next, z_next);
                cell.second[25] = calc_index(x,      y_next, z_next);
                cell.second[26] = calc_index(x_next, y_next, z_next);
            } // for z
            } // for y
        } // for x (in parallel)

        this->make(neighbors, sys, pot);
        return;
    }

    //XXX do NOT call this from parallel region
    void make(neighbor_list_type& neighbors,
              const system_type& sys, const potential_type& pot) override
    {
	MJOLNIR_GET_DEFAULT_LOGGER_DEBUG();
	MJOLNIR_LOG_FUNCTION_DEBUG();

        // `participants` is a list that contains indices of particles that are
        // related to the potential.
        const auto& participants = pot.participants();

        neighbors.clear();
        if(index_by_cell_    .size() != sys.size() ||
           index_by_cell_buf_.size() != sys.size())
        {
            index_by_cell_    .resize(sys.size());
            index_by_cell_buf_.resize(sys.size());
        }

#pragma omp parallel for
        for(std::size_t i=0; i<participants.size(); ++i)
        {
            const auto idx = participants[i];
            index_by_cell_[i] =
                std::make_pair(idx, this->calc_index(sys.position(idx)));
        }

        omp::sort(this->index_by_cell_, this->index_by_cell_buf_,
                  [](const particle_cell_idx_pair& lhs,
                     const particle_cell_idx_pair& rhs) noexcept -> bool {
                      return lhs.second < rhs.second;
                  });

        // assign first and last iterator for each cells
#pragma omp parallel for
        for(std::size_t cell_idx=0; cell_idx<cell_list_.size(); ++cell_idx)
        {
            auto iter = std::find_if(index_by_cell_.cbegin(), index_by_cell_.cend(),
                [cell_idx](const particle_cell_idx_pair& item) noexcept -> bool {
                    return item.second == cell_idx;
                });
            if(iter == index_by_cell_.cend())
            {
                cell_list_[cell_idx].first = make_range(iter, iter);
                continue;
            }
            const auto first = iter; // the first iter of the range
            while(iter != index_by_cell_.cend() && iter->second == cell_idx)
            {
                ++iter;
            }
            cell_list_[cell_idx].first = make_range(first, iter);
        }

        const real_type r_c  = cutoff_ * (1 + margin_);
        const real_type r_c2 = r_c * r_c;

//XXX ParallelNeighborList consumes quite a lot of memory resources and makes
//XXX both construction and access slower (especially when system has a small
//XXX number of particles). Because of this, after some benchmarking, I found
//XXX that normal NeighborList works good for most of the cases. Some part of
//XXX neighbor-list construction cannot be parallelized, but it becomes still
//XXX faster.

        std::vector<neighbor_type> partner;
        for(std::size_t idx=0; idx<participants.size(); ++idx)
        {
            partner.clear();
            const auto  i    = participants[idx];
            const auto& ri   = sys.position(i);
            const auto& cell = cell_list_[this->calc_index(ri)];

            MJOLNIR_LOG_DEBUG("particle position ", sys.position(i));
            MJOLNIR_LOG_DEBUG("cell index ",        calc_index(ri));
            MJOLNIR_LOG_DEBUG("making verlet list for index ", i);

            for(std::size_t cidx : cell.second) // for all adjacent cells...
            {
                MJOLNIR_LOG_DEBUG("neighbor cell index ", cidx);
                for(auto pici : cell_list_[cidx].first)
                {
                    const auto j = pici.first;
                    MJOLNIR_LOG_DEBUG("looking particle ", j);
                    if(j <= i || !pot.has_interaction(i, j))
                    {
                        continue;
                    }
                    // here we don't need to search `participants` because
                    // cell list contains only participants. non-related
                    // particles are already filtered.

                    const auto& rj = sys.position(j);
                    if(math::length_sq(sys.adjust_direction(rj - ri)) < r_c2)
                    {
                        MJOLNIR_LOG_DEBUG("add index ", j, " to list ", i);
                        partner.emplace_back(j, pot.prepare_params(i, j));
                    }
                }
            }
            // make the result consistent with NaivePairCalculation...
            std::sort(partner.begin(), partner.end());
            neighbors.add_list_for(i, partner.begin(), partner.end());
        }

        this->current_margin_ = cutoff_ * margin_;
        return ;
    }

    //XXX do NOT call this from `parallel` region.
    void update(neighbor_list_type& neighbors, const real_type dmargin,
                const system_type& sys, const potential_type& pot) override
    {
        this->current_margin_ -= dmargin;

        if(this->current_margin_ < 0.)
        {
            this->make(neighbors, sys, pot);
        }
        return ;
    }

    real_type cutoff() const noexcept override {return this->cutoff_;}
    real_type margin() const noexcept override {return this->margin_;}

  private:

    // calc cell index of the position
    std::size_t calc_index(const coordinate_type& pos) const noexcept
    {
        constexpr std::int64_t d = dim();
        const auto x = std::int64_t(std::floor(math::X(pos) * r_cell_size_)) % d;
        const auto y = std::int64_t(std::floor(math::Y(pos) * r_cell_size_)) % d;
        const auto z = std::int64_t(std::floor(math::Z(pos) * r_cell_size_)) % d;

        return this->calc_index((x<0) ? x+d : x, (y<0) ? y+d : y, (z<0) ? z+d : z);
    }

    std::size_t calc_index(const std::size_t x, const std::size_t y,
                           const std::size_t z) const noexcept
    {
        return x + dim_size() * y + dim_size() * dim_size() * z;
    }

    void set_cutoff(const real_type c) noexcept
    {
        this->cutoff_ = c;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon()));
    }
    void set_margin(const real_type m) noexcept
    {
        this->margin_ = m;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon()));
    }

  private:

    real_type cutoff_;
    real_type margin_;
    real_type current_margin_;
    real_type r_cell_size_;

    neighbor_list_type        neighbors_;
    cell_list_type            cell_list_;
    cell_index_container_type index_by_cell_;
    cell_index_container_type index_by_cell_buf_; // buffer for sort
    // index_by_cell_ has {particle idx, cell idx} and sorted by cell idx
    // first term of cell list contains first and last idx of index_by_cell
};
} // mjolnir

#ifdef MJOLNIR_SEPARATE_BUILD
#include <mjolnir/potential/global/DebyeHuckelPotential.hpp>
#include <mjolnir/potential/global/ExcludedVolumePotential.hpp>
#include <mjolnir/potential/global/LennardJonesPotential.hpp>
#include <mjolnir/potential/global/UniformLennardJonesPotential.hpp>

namespace mjolnir
{
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, DebyeHuckelPotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, DebyeHuckelPotential<float >>;

extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, ExcludedVolumePotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, ExcludedVolumePotential<float >>;

extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, LennardJonesPotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, LennardJonesPotential<float >>;

extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<double, UnlimitedBoundary>, UniformLennardJonesPotential<double>>;
extern template class UnlimitedGridCellList<OpenMPSimulatorTraits<float,  UnlimitedBoundary>, UniformLennardJonesPotential<float >>;
}
#endif // MJOLNIR_SEPARATE_BUILD
#endif/* MJOLNIR_UNLIMITED_GRID_CELL_LIST */
<|endoftext|>


<commit_before>#pragma once
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>

#define _mgl_str(x) #x
#define _mgl_xstr(x) _mgl_str(x)
#define mgl_mod _mgl_xstr(MODERNGL_MODULE)
#define mgl_ext mgl_mod ".mgl"

/* Wrapper classes for internal objects are defined in python. They must have __slots__ defined.
 * A slot can be accessed in O(1) once detect_class(...) and slot_offset(...) is called.
 */

#define SLOT(obj, type, offset) (*(type **)((char *)obj + offset))

/* Shortcuts */

#define NEW_REF(obj) (Py_INCREF(obj), obj)

#ifndef Py_SETREF
#define Py_SETREF(op, op2)                      \
    do {                                        \
        PyObject *_py_tmp = (PyObject *)(op);   \
        (op) = (op2);                           \
        Py_DECREF(_py_tmp);                     \
    } while (0)
#endif

#ifndef Py_XSETREF
#define Py_XSETREF(op, op2)                     \
    do {                                        \
        PyObject *_py_tmp = (PyObject *)(op);   \
        (op) = (op2);                           \
        Py_XDECREF(_py_tmp);                    \
    } while (0)
#endif

/* Classes defined in python must be instantiated using new_object(...)
 * The allocated memory is initialized to zero.
 * Slots can be set using the SLOT(...) macro.
 */
inline PyObject * _new_object(PyTypeObject * type) {
    PyObject * res = 0;
    Py_INCREF(type);
    if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
        res = PyObject_GC_New(PyObject, type);
    } else {
        res = PyObject_New(PyObject, type);
    }
    return res;
}

#define new_object(type, typeobj) (type *)_new_object(typeobj)
#define call_function(function, ...) PyObject_CallFunctionObjArgs(function, __VA_ARGS__, (void *)0)

inline void replace_object(PyObject *& src, PyObject * dst) {
    Py_INCREF(dst);
    Py_DECREF(src);
    src = dst;
}
<commit_msg>clear slots on new<commit_after>#pragma once
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>

#define _mgl_str(x) #x
#define _mgl_xstr(x) _mgl_str(x)
#define mgl_mod _mgl_xstr(MODERNGL_MODULE)
#define mgl_ext mgl_mod ".mgl"

/* Wrapper classes for internal objects are defined in python. They must have __slots__ defined.
 * A slot can be accessed in O(1) once detect_class(...) and slot_offset(...) is called.
 */

#define SLOT(obj, type, offset) (*(type **)((char *)obj + offset))

/* Shortcuts */

#define NEW_REF(obj) (Py_INCREF(obj), obj)

#ifndef Py_SETREF
#define Py_SETREF(op, op2)                      \
    do {                                        \
        PyObject *_py_tmp = (PyObject *)(op);   \
        (op) = (op2);                           \
        Py_DECREF(_py_tmp);                     \
    } while (0)
#endif

#ifndef Py_XSETREF
#define Py_XSETREF(op, op2)                     \
    do {                                        \
        PyObject *_py_tmp = (PyObject *)(op);   \
        (op) = (op2);                           \
        Py_XDECREF(_py_tmp);                    \
    } while (0)
#endif

/* Classes defined in python must be instantiated using new_object(...)
 * The allocated memory is initialized to zero.
 * Slots can be set using the SLOT(...) macro.
 */
inline PyObject * _new_object(PyTypeObject * type) {
    PyObject * res = 0;
    Py_INCREF(type);
    if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
        res = PyObject_GC_New(PyObject, type);
        for (int i = 0; res->ob_type->tp_members[i].name; ++i) {
            SLOT(res, PyObject, (int)res->ob_type->tp_members[i].offset) = 0;
        }
    } else {
        res = PyObject_New(PyObject, type);
    }
    return res;
}

#define new_object(type, typeobj) (type *)_new_object(typeobj)
#define call_function(function, ...) PyObject_CallFunctionObjArgs(function, __VA_ARGS__, (void *)0)

inline void replace_object(PyObject *& src, PyObject * dst) {
    Py_INCREF(dst);
    Py_DECREF(src);
    src = dst;
}
<|endoftext|>