<commit_before>// arm-poky-linux-gnueabi-gcc -lopencv_video -lopencv_core -lopencv_highgui -lopencv_imgproc -lstdc++ -lpthread -shared-libgcc opencv.cpp -o opencv

#include "evision.h"
#include "tracer.h"
#include "gpio.h"

// Global variables
GPIO pwm_right(1, "out"), pwm_left(3, "out"); // led_right(2 , "out");
GPIO led_front(5, "out"), led_R(4, "out"), start(7 ,"out"); // 0,2,6 bulit
int high_right = 600, high_left = 600, period = 20000; //PWM high time in us
int top_edge = 50, servo_offset = 0, road_offset = 0;

// GUI globals
cv::Mat guiframe;
bool new_frame = false;
bool running = true;

// Window titles
char main_window_name[] = "Lightning Asystant :: Team eVision";
char settings_window_name[] = "Settings :: Team eVision";

// Settings variables
int settings_show_step = 0;
int settings_contrast = 0;
int settings_blur = 1;
int settings_threshold = 128;
int settings_servo_offset = 500;
int settings_road_approx = 5;
int settings_middle_line = 240;

// Graphics
std::vector<std::vector<cv::Point>> contours;

//Functions declaration
void pwm_servo_right(int);
void pwm_servo_left(int);
int car_position(int);
int obstacle_position(int);

int main(int argc, char** argv)
{
    pthread_t processing_thread;
    long time_old;
    int fps_counter = 0;
    int gui_key;

	// for cpu affinity
	cpu_set_t cpuset;
	int cpu = 0;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    // process priority
    setpriority(PRIO_PROCESS, 0, -20);

    // GUI setup
	cv::namedWindow(main_window_name);

	// Setup window
	cv::namedWindow(settings_window_name);
	cv::createTrackbar("Show Step   ", settings_window_name, &settings_show_step, LAST_STEP-1);
	cv::createTrackbar("Contrast    ", settings_window_name, &settings_contrast, 1);
	cv::createTrackbar("Mean Blur   ", settings_window_name, &settings_blur, 1);
	cv::createTrackbar("Threshold   ", settings_window_name, &settings_threshold, 255);
	cv::createTrackbar("Road Approx ", settings_window_name, &settings_road_approx, 30);
	cv::createTrackbar("Middle Line ", settings_window_name, &settings_middle_line, 320);
	cv::createTrackbar("Servo Offset", settings_window_name, &settings_servo_offset, 1000);
	cv::createTrackbar("Servo Right ", settings_window_name, &high_right, 1500);
	cv::createTrackbar("Servo Left  ", settings_window_name, &high_left, 1500);

	pthread_create(&processing_thread, NULL, processing_thread_function, NULL);
	//pthread_create(&pwm_thread, NULL, pwm_thread_function, NULL);

    while(running){

    	while(!new_frame){ } // loop

		cv::imshow(main_window_name, guiframe);

		// calculate fps
		if(time(NULL) != time_old){
			add_info(fps_counter);
			fps_counter = 1;
			time_old = time(NULL);
		} else {
			fps_counter++;
		}

		new_frame = 0;

		gui_key = cv::waitKey(5);
		if(gui_key >= 0) {
			gui_key %= 0xFF;

			// ESC
			if((gui_key == 43) || (gui_key == 27)){
				led_front.low();
				led_R.low();
				running = false;
			} else if((gui_key == 48) || (gui_key == 32)) {
				start.high(); // 1 = start/stop
				usleep(50000);
				start.low();
			} else if((gui_key == 50) || (gui_key == 66)) {
				led_front.toggle(); // 2 = faruri
			} else if((gui_key == 51) || (gui_key == 67)) {
				led_R.toggle(); // 3 = far pieton
			} else {
				std::cout << gui_key << std::endl;
			}
		}
    }

	pthread_join(processing_thread, NULL);

    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

void send_frame_to_gui(cv::Mat &frame, int step){
	if((new_frame == 0) && (step == settings_show_step)){
		//cv::pyrUp(frame, guiframe);
		frame.copyTo(guiframe);
		new_frame = 1;
	}
}

bool contour_area(int a, int b){
	return cv::contourArea(contours[a]) > cv::contourArea(contours[b]);
}

bool get_obstacle(
	int parent,
	std::vector<std::vector<cv::Point>> contours,
	std::vector<cv::Vec4i> hierarchy,
	cv::Rect &obstacle){

	int start = hierarchy[parent][2];
	int closest = -1;
	bool found = false;

	while(start > 0){

		if(closest == -1){
			closest = start;
			found = true;
		} else if(cv::boundingRect(contours[start]).y > cv::boundingRect(contours[closest]).y){
			closest = start;
		}

		start = hierarchy[start][0];
	}

	if(found){
		obstacle = cv::boundingRect(contours[closest]);
	}

	return found;
}

void draw_obstacles(cv::Mat &threshold_frame, cv::Mat &cam_frame){
	std::vector<std::vector<cv::Point>> road(2);
	std::vector<cv::Vec4i> hierarchy;

	cv::findContours(threshold_frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
	if(contours.size() > 1){

		// create index vector
		std::vector<int> contour_indexes(contours.size());

		for(unsigned int i = 0; i < contours.size(); i++){
			contour_indexes[i] = i;
		}

		// sorting index vector acording to controur area
		std::sort(contour_indexes.begin(), contour_indexes.end(), contour_area);

		cv::approxPolyDP(cv::Mat(contours[contour_indexes[0]]), road[0], settings_road_approx, true);
		cv::approxPolyDP(cv::Mat(contours[contour_indexes[1]]), road[1], settings_road_approx, true);

		// validate road detection
		int road_edge = -1;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y > 235) && (road_edge == -1)){
				road_edge = road[0][i].x;

			} else if((road[0][i].y > 235) && (road[0][i].x < road_edge)){

				road_edge = road[0][i].x;
			}
		}

		if(road_edge < 0)
			return ;

		for(unsigned int i = 0; i < road[1].size(); ++i){
			if((road[1][i].y > 235) && (road[1][i].x > road_edge)){

				// wrong detection
				return;
			}
		}

		// paint road area
		cv::drawContours(cam_frame, road, 0, cv::Scalar(0, 255 ,0), 2);
		cv::drawContours(cam_frame, road, 1, cv::Scalar(255, 0, 0), 2);

		// get road offset
		// reference point is the left most point from the top edge of road contour
		int new_road_offset = 600;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y == top_edge) && (road[0][i].x < new_road_offset)){
				new_road_offset = road[0][i].x;
			}
		}

		if((new_road_offset > 50) && (new_road_offset < 250)){
			road_offset = new_road_offset;
		}

		//std::cout << road_offset << std::endl;

		cv::Rect obstacle;
		if(get_obstacle(contour_indexes[0], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(0, 0, 255));
			//std::cout << cv::Point(obstacle.x + (obstacle.width / 2), obstacle.y + (obstacle.height / 2)) << std::endl;
			pwm_servo_right(high_right + servo_offset + road_offset + car_position(obstacle.y + (obstacle.height / 2)));
		}

		if(get_obstacle(contour_indexes[1], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(255, 0, 255));

   			pwm_servo_left(high_left + servo_offset + road_offset + obstacle_position(0));
		}

		cv::line(cam_frame, cv::Point(settings_middle_line, 320), cv::Point(settings_middle_line, top_edge), cv::Scalar(0, 255, 255));
	}
}

void *processing_thread_function(void* unsused)
{
	cv::VideoCapture 	cap(0); // camera interface
    cv::Mat 			frame, cam_frame, bw_frame, blur_frame, contrast_frame;
    cv::Mat				threshold_frame, canny_frame, contour_frame;
    Tracer				processing_tracer;

    // for cpu affinity
	cpu_set_t cpuset;
	int cpu = 1;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    if(!cap.isOpened())  // check if we succeeded
    {
        std::cout << "Could not open default video device" << std::endl;
        pthread_exit(NULL);

    }

   	while(running) {
		if( !cap.read(frame) ){
			std::cout << "Camera was disconected";
			break;
		}

		cv::pyrDown(frame, cam_frame);
		send_frame_to_gui(cam_frame, SENSOR_IMAGE);
		processing_tracer.start();

		// All processing are done on gray image
		cv::cvtColor(cam_frame, bw_frame, CV_BGR2GRAY);
		processing_tracer.event("Convert to Gray");
		send_frame_to_gui(bw_frame, GRAY_IMAGE);

		// Increase contrast by distributing color histogram to contain all values
		if(settings_contrast){
			cv::equalizeHist(bw_frame, contrast_frame);
		} else {
			contrast_frame = bw_frame;
		}
		processing_tracer.event("Equalize histogram");
		send_frame_to_gui(contrast_frame, CONTRAST_IMAGE);

		// Apply a special blur filter which preserves edges
		if(settings_blur){
			cv::medianBlur(contrast_frame, blur_frame, 7);
		} else {
			blur_frame = contrast_frame;
		}
		processing_tracer.event("Median blur");
		send_frame_to_gui(blur_frame, BLUR_IMAGE);

		// detect edges using histeresys
		cv::Canny(contrast_frame, canny_frame, 30, 100);
		processing_tracer.event("Edge detection");
		send_frame_to_gui(canny_frame, CANNY_IMAGE);

		// Apply threshhold
		threshold(blur_frame, threshold_frame, settings_threshold, 255, CV_THRESH_BINARY);
		// Disable image top from detection to remove false edges
		cv::rectangle(threshold_frame, cv::Rect(0, 0, 320, top_edge), cv::Scalar(0), CV_FILLED);
		processing_tracer.event("Appling threshold");
		send_frame_to_gui(threshold_frame, THRESHOLD_IMAGE);

		// detect and paint contours
		draw_obstacles(threshold_frame, cam_frame);
		processing_tracer.event("Contour detection");
		send_frame_to_gui(cam_frame, CONTOUR_IMAGE);
	}

	processing_tracer.end();
	pthread_exit(NULL);
}

void pwm_servo_right(int h_r){
	int static local_hr = 0;
	if(abs(h_r - local_hr) > 5){
		local_hr = h_r;
		pwm_right.high();
		usleep(local_hr);
		pwm_right.low();
		usleep(period - local_hr);
	}
}

void pwm_servo_left(int h_l){
	int static local_hl = 0;
	if(abs(h_l - local_hl) > 5){
		local_hl = h_l;
		pwm_left.high();
		usleep(local_hl);
		pwm_left.low();
		usleep(period - local_hl);
	}
}

int obstacle_position(int y_position){
	if(y_position > top_edge){
		return int ( 0.9 * y_position + 15);
	} else {
		return 0;
	}
}

int car_position(int y_position){
	if(y_position > top_edge){
		return 1;
	} else {
		return 0;
	}
}

void add_info(int fps){
	// white canvas
	cv::Mat img_info (25, 320, CV_8UC3, cv::Scalar(255, 255, 255));

	cv::putText(img_info, std::string("FPS: ") + std::to_string(fps), cv::Point(5, 20),
			cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cv::Scalar(0,0,255), 1, CV_AA);

	cv::imshow(settings_window_name, img_info);
}
<commit_msg>Working object detection<commit_after>// arm-poky-linux-gnueabi-gcc -lopencv_video -lopencv_core -lopencv_highgui -lopencv_imgproc -lstdc++ -lpthread -shared-libgcc opencv.cpp -o opencv

#include "evision.h"
#include "tracer.h"
#include "gpio.h"

// Global variables
GPIO pwm_right(1, "out"), pwm_left(3, "out"); // led_right(2 , "out");
GPIO led_front(5, "out"), led_R(4, "out"), start(7 ,"out"); // 0,2,6 bulit
int high_right = 600, high_left = 600, period = 20000; //PWM high time in us
int top_edge = 50, servo_offset = 0, road_offset = 0;

// GUI globals
cv::Mat guiframe;
bool new_frame = false;
bool running = true;

// Window titles
char main_window_name[] = "Lightning Asystant :: Team eVision";
char settings_window_name[] = "Settings :: Team eVision";

// Settings variables
int settings_show_step = 0;
int settings_contrast = 0;
int settings_blur = 1;
int settings_threshold = 128;
int settings_servo_offset = 500;
int settings_road_approx = 5;
int settings_middle_line = 240;

// Graphics
std::vector<std::vector<cv::Point>> contours;

//Functions declaration
void pwm_servo_right(int);
void pwm_servo_left(int);
int car_position(int);
int obstacle_position(int);

int main(int argc, char** argv)
{
    pthread_t processing_thread;
    long time_old;
    int fps_counter = 0;
    int gui_key;

	// for cpu affinity
	cpu_set_t cpuset;
	int cpu = 0;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    // process priority
    setpriority(PRIO_PROCESS, 0, -20);

    // GUI setup
	cv::namedWindow(main_window_name);

	// Setup window
	cv::namedWindow(settings_window_name);
	cv::createTrackbar("Show Step   ", settings_window_name, &settings_show_step, LAST_STEP-1);
	cv::createTrackbar("Contrast    ", settings_window_name, &settings_contrast, 1);
	cv::createTrackbar("Mean Blur   ", settings_window_name, &settings_blur, 1);
	cv::createTrackbar("Threshold   ", settings_window_name, &settings_threshold, 255);
	cv::createTrackbar("Road Approx ", settings_window_name, &settings_road_approx, 30);
	cv::createTrackbar("Middle Line ", settings_window_name, &settings_middle_line, 320);
	cv::createTrackbar("Servo Offset", settings_window_name, &settings_servo_offset, 1000);
	cv::createTrackbar("Servo Right ", settings_window_name, &high_right, 1500);
	cv::createTrackbar("Servo Left  ", settings_window_name, &high_left, 1500);

	pthread_create(&processing_thread, NULL, processing_thread_function, NULL);
	//pthread_create(&pwm_thread, NULL, pwm_thread_function, NULL);

    while(running){

    	while(!new_frame){ } // loop

		cv::imshow(main_window_name, guiframe);

		// calculate fps
		if(time(NULL) != time_old){
			add_info(fps_counter);
			fps_counter = 1;
			time_old = time(NULL);
		} else {
			fps_counter++;
		}

		new_frame = 0;

		gui_key = cv::waitKey(5);
		if(gui_key >= 0) {
			gui_key %= 0xFF;

			// ESC
			if((gui_key == 43) || (gui_key == 27)){
				led_front.low();
				led_R.low();
				running = false;
			} else if((gui_key == 48) || (gui_key == 32)) {
				start.high(); // 1 = start/stop
				usleep(50000);
				start.low();
			} else if((gui_key == 50) || (gui_key == 66)) {
				led_front.toggle(); // 2 = faruri
			} else if((gui_key == 51) || (gui_key == 67)) {
				led_R.toggle(); // 3 = far pieton
			} else {
				std::cout << gui_key << std::endl;
			}
		}
    }

	pthread_join(processing_thread, NULL);

    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

void send_frame_to_gui(cv::Mat &frame, int step){
	if((new_frame == 0) && (step == settings_show_step)){
		//cv::pyrUp(frame, guiframe);
		frame.copyTo(guiframe);
		new_frame = 1;
	}
}

bool contour_area(int a, int b){
	return cv::contourArea(contours[a]) > cv::contourArea(contours[b]);
}

bool get_obstacle(
	int parent,
	std::vector<std::vector<cv::Point>> contours,
	std::vector<cv::Vec4i> hierarchy,
	cv::Rect &obstacle){

	int start = hierarchy[parent][2];
	int closest = -1;
	bool found = false;

	while(start > 0){

		if(closest == -1){
			closest = start;
			found = true;
		} else if(cv::boundingRect(contours[start]).y > cv::boundingRect(contours[closest]).y){
			closest = start;
		}

		start = hierarchy[start][0];
	}

	if(found){
		obstacle = cv::boundingRect(contours[closest]);
	}

	return found;
}

void draw_obstacles(cv::Mat &threshold_frame, cv::Mat &cam_frame){
	std::vector<std::vector<cv::Point>> road(2);
	std::vector<cv::Vec4i> hierarchy;

	cv::findContours(threshold_frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
	if(contours.size() > 1){

		// create index vector
		std::vector<int> contour_indexes(contours.size());

		for(unsigned int i = 0; i < contours.size(); i++){
			contour_indexes[i] = i;
		}

		// sorting index vector acording to controur area
		std::sort(contour_indexes.begin(), contour_indexes.end(), contour_area);

		cv::approxPolyDP(cv::Mat(contours[contour_indexes[0]]), road[0], settings_road_approx, true);
		cv::approxPolyDP(cv::Mat(contours[contour_indexes[1]]), road[1], settings_road_approx, true);

		// validate road detection
		int road_edge = -1;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y > 235) && (road_edge == -1)){
				road_edge = road[0][i].x;

			} else if((road[0][i].y > 235) && (road[0][i].x < road_edge)){

				road_edge = road[0][i].x;
			}
		}

		if(road_edge < 0)
			return ;

		for(unsigned int i = 0; i < road[1].size(); ++i){
			if((road[1][i].y > 235) && (road[1][i].x > road_edge)){

				// wrong detection
				return;
			}
		}

		// paint road area
		cv::drawContours(cam_frame, road, 0, cv::Scalar(0, 255 ,0), 2);
		cv::drawContours(cam_frame, road, 1, cv::Scalar(255, 0, 0), 2);

		// get road offset
		// reference point is the left most point from the top edge of road contour
		int new_road_offset = 600;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y == top_edge) && (road[0][i].x < new_road_offset)){
				new_road_offset = road[0][i].x;
			}
		}

		if((new_road_offset > 50) && (new_road_offset < 250)){
			road_offset = new_road_offset;
		}

		//std::cout << road_offset << std::endl;

		cv::Rect obstacle;
		if(get_obstacle(contour_indexes[0], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(0, 0, 255));
			//std::cout << cv::Point(obstacle.x + (obstacle.width / 2), obstacle.y + (obstacle.height / 2)) << std::endl;
			pwm_servo_right(high_right + servo_offset + road_offset + obstacle_position(obstacle.y + (obstacle.height / 2)));
		}

		if(get_obstacle(contour_indexes[1], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(255, 0, 255));

   			pwm_servo_left(high_left + servo_offset + road_offset + car_position(0));
		}

		cv::line(cam_frame, cv::Point(settings_middle_line, 320), cv::Point(settings_middle_line, top_edge), cv::Scalar(0, 255, 255));
	}
}

void *processing_thread_function(void* unsused)
{
	cv::VideoCapture 	cap(0); // camera interface
    cv::Mat 			frame, cam_frame, bw_frame, blur_frame, contrast_frame;
    cv::Mat				threshold_frame, canny_frame, contour_frame;
    Tracer				processing_tracer;

    // for cpu affinity
	cpu_set_t cpuset;
	int cpu = 1;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    if(!cap.isOpened())  // check if we succeeded
    {
        std::cout << "Could not open default video device" << std::endl;
        pthread_exit(NULL);

    }

   	while(running) {
		if( !cap.read(frame) ){
			std::cout << "Camera was disconected";
			break;
		}

		cv::pyrDown(frame, cam_frame);
		send_frame_to_gui(cam_frame, SENSOR_IMAGE);
		processing_tracer.start();

		// All processing are done on gray image
		cv::cvtColor(cam_frame, bw_frame, CV_BGR2GRAY);
		processing_tracer.event("Convert to Gray");
		send_frame_to_gui(bw_frame, GRAY_IMAGE);

		// Increase contrast by distributing color histogram to contain all values
		if(settings_contrast){
			cv::equalizeHist(bw_frame, contrast_frame);
		} else {
			contrast_frame = bw_frame;
		}
		processing_tracer.event("Equalize histogram");
		send_frame_to_gui(contrast_frame, CONTRAST_IMAGE);

		// Apply a special blur filter which preserves edges
		if(settings_blur){
			cv::medianBlur(contrast_frame, blur_frame, 7);
		} else {
			blur_frame = contrast_frame;
		}
		processing_tracer.event("Median blur");
		send_frame_to_gui(blur_frame, BLUR_IMAGE);

		// detect edges using histeresys
		cv::Canny(contrast_frame, canny_frame, 30, 100);
		processing_tracer.event("Edge detection");
		send_frame_to_gui(canny_frame, CANNY_IMAGE);

		// Apply threshhold
		threshold(blur_frame, threshold_frame, settings_threshold, 255, CV_THRESH_BINARY);
		// Disable image top from detection to remove false edges
		cv::rectangle(threshold_frame, cv::Rect(0, 0, 320, top_edge), cv::Scalar(0), CV_FILLED);
		processing_tracer.event("Appling threshold");
		send_frame_to_gui(threshold_frame, THRESHOLD_IMAGE);

		// detect and paint contours
		draw_obstacles(threshold_frame, cam_frame);
		processing_tracer.event("Contour detection");
		send_frame_to_gui(cam_frame, CONTOUR_IMAGE);
	}

	processing_tracer.end();
	pthread_exit(NULL);
}

void pwm_servo_right(int h_r){
	int static local_hr = 0;
	if(abs(h_r - local_hr) > 5){
		local_hr = h_r;
		pwm_right.high();
		usleep(local_hr);
		pwm_right.low();
		usleep(period - local_hr);
	}
}

void pwm_servo_left(int h_l){
	int static local_hl = 0;
	if(abs(h_l - local_hl) > 5){
		local_hl = h_l;
		pwm_left.high();
		usleep(local_hl);
		pwm_left.low();
		usleep(period - local_hl);
	}
}

int obstacle_position(int y_position){
	if(y_position > top_edge){
		return int ( 0.9 * y_position + 15);
	} else {
		return 0;
	}
}

int car_position(int y_position){
	if(y_position > top_edge){
		return 1;
	} else {
		return 0;
	}
}

void add_info(int fps){
	// white canvas
	cv::Mat img_info (25, 320, CV_8UC3, cv::Scalar(255, 255, 255));

	cv::putText(img_info, std::string("FPS: ") + std::to_string(fps), cv::Point(5, 20),
			cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cv::Scalar(0,0,255), 1, CV_AA);

	cv::imshow(settings_window_name, img_info);
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// Antioch - A Gas Dynamics Thermochemistry Library
//
// Copyright (C) 2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-
//
// $Id$
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

// C++
#include <limits>
#include <string>
#include <vector>

// Antioch
#include "antioch/vector_utils.h"

#include "antioch/antioch_asserts.h"
#include "antioch/chemical_species.h"
#include "antioch/chemical_mixture.h"
#include "antioch/reaction_set.h"
#include "antioch/read_reaction_set_data_xml.h"
#include "antioch/cea_thermo.h"
#include "antioch/kinetics_evaluator.h"

template <typename Scalar>
int tester(const std::string& input_name)
{
  using std::abs;

  std::vector<std::string> species_str_list;
  const unsigned int n_species = 5;
  species_str_list.reserve(n_species);
  species_str_list.push_back( "N2" );
  species_str_list.push_back( "O2" );
  species_str_list.push_back( "N" );
  species_str_list.push_back( "O" );
  species_str_list.push_back( "NO" );

  Antioch::ChemicalMixture<Scalar> chem_mixture( species_str_list );
  Antioch::ReactionSet<Scalar> reaction_set( chem_mixture );
  Antioch::CEAThermodynamics<Scalar> thermo( chem_mixture );

  Antioch::read_reaction_set_data_xml<Scalar>( input_name, true, reaction_set );

  const Scalar T = 1500.0;
  const Scalar P = 1.0e5;

  // Mass fractions
  std::vector<Scalar> Y(n_species,0.2);

  const Scalar R_mix = chem_mixture.R(Y);

  const Scalar rho = P/(R_mix*T);

  std::vector<Scalar> molar_densities(n_species,0.0);
  chem_mixture.molar_densities(rho,Y,molar_densities);

  std::vector<Scalar> h_RT_minus_s_R(n_species);
  std::vector<Scalar> dh_RT_minus_s_R_dT(n_species);

  typedef typename Antioch::CEAThermodynamics<Scalar>::template Cache<Scalar> Cache;
  thermo.h_RT_minus_s_R(Cache(T),h_RT_minus_s_R);
  thermo.dh_RT_minus_s_R_dT(Cache(T),dh_RT_minus_s_R_dT);

  Antioch::KineticsEvaluator<Scalar> kinetics( reaction_set, 0 );

  std::vector<Scalar> omega_dot(n_species);
  std::vector<Scalar> domega_dot_dT(n_species);

  std::vector<std::vector<Scalar> > domega_dot_drho_s(n_species);
  for( unsigned int s = 0; s < n_species; s++ )
    {
      domega_dot_drho_s[s].resize(n_species);
    }

  kinetics.compute_mass_sources( T, rho, R_mix, Y, molar_densities, h_RT_minus_s_R, omega_dot );

  kinetics.compute_mass_sources_and_derivs( T, rho, R_mix, Y, molar_densities, h_RT_minus_s_R, dh_RT_minus_s_R_dT,
                                            omega_dot, domega_dot_dT, domega_dot_drho_s );

  for( unsigned int s = 0; s < n_species; s++)
    {
      std::cout << std::scientific << std::setprecision(16)
		<< "omega_dot(" << chem_mixture.chemical_species()[s]->species() << ") = "
		<< omega_dot[s] << std::endl;
    }

  for( unsigned int s = 0; s < n_species; s++)
    {
      std::cout << std::scientific << std::setprecision(16)
                << "domega_dot_dT(" << chem_mixture.chemical_species()[s]->species() << ") = "
                << domega_dot_dT[s] << std::endl;
    }

  for( unsigned int s = 0; s < n_species; s++)
    {
      for( unsigned int t = 0; t < n_species; t++)
        {
          std::cout << std::scientific << std::setprecision(16)
                    << "domega_dot_drho_s(" << chem_mixture.chemical_species()[s]->species()
                    << ", " << chem_mixture.chemical_species()[t]->species() << ") = "
                    << domega_dot_drho_s[s][t] << std::endl;
        }
    }

  int return_flag = 0;

  const Scalar tol = std::numeric_limits<Scalar>::epsilon() * 100;

  // Regression values for omega_dot
  std::vector<Scalar> omega_dot_reg(n_species);
  omega_dot_reg[0] =  7.9004530802650654e+04;
  omega_dot_reg[1] = -3.4113853617637843e+05;
  omega_dot_reg[2] = -1.8898881857838202e+05;
  omega_dot_reg[3] =  2.1551399274321867e+05;
  omega_dot_reg[4] =  2.3560883120889112e+05;

  for( unsigned int s = 0; s < n_species; s++)
    {
      const Scalar rel_error = abs( (omega_dot[s] - omega_dot_reg[s])/omega_dot_reg[s]);
      if( rel_error > tol )
        {
          return_flag = 1;
        }
    }

  // Regression values for domega_dot_dT
  std::vector<Scalar> domega_dot_reg_dT(n_species);
  domega_dot_reg_dT[0] =  1.9573634782953712e+02;
  domega_dot_reg_dT[1] = -5.1996539987130484e+02;
  domega_dot_reg_dT[2] = -3.2528809609986996e+02;
  domega_dot_reg_dT[3] =  3.7199081589605311e+02;
  domega_dot_reg_dT[4] =  2.7752633224558451e+02;

  for( unsigned int s = 0; s < n_species; s++)
    {
      const Scalar rel_error = abs( (domega_dot_dT[s] - domega_dot_reg_dT[s])/domega_dot_reg_dT[s]);
      if( rel_error > tol )
        {
          return_flag = 1;
        }
    }

  // Regression values for domega_dot_drho_s
  std::vector<std::vector<Scalar> > domega_dot_reg_drhos(n_species);
  for( unsigned int s = 0; s < n_species; s++)
    {
      domega_dot_reg_drhos[s].resize(n_species);
    }

  domega_dot_reg_drhos[0][0] = 1.5777705018045012e+02;
  domega_dot_reg_drhos[0][1] = 1.3813389268698828e+02;
  domega_dot_reg_drhos[0][2] = 2.3115223534864103e+06;
  domega_dot_reg_drhos[0][3] = 1.1840007503997479e+03;
  domega_dot_reg_drhos[0][4] = 2.3043581130447080e+06;

  domega_dot_reg_drhos[1][0] =  7.1306539959731154e+01;
  domega_dot_reg_drhos[1][1] = -9.9638812606792040e+06;
  domega_dot_reg_drhos[1][2] = -9.9632306241494343e+06;
  domega_dot_reg_drhos[1][3] =  3.7459340498153397e+03;
  domega_dot_reg_drhos[1][4] =  1.1289308740617102e+02;

  domega_dot_reg_drhos[2][0] = -1.7978873571638729e+02;
  domega_dot_reg_drhos[2][1] = -4.3618737551808357e+06;
  domega_dot_reg_drhos[2][2] = -5.5244116479589976e+06;
  domega_dot_reg_drhos[2][3] = -4.3214935810689167e+03;
  domega_dot_reg_drhos[2][4] = -1.1526845416778582e+06;

  domega_dot_reg_drhos[3][0] = -9.6448385232075168e+01;
  domega_dot_reg_drhos[3][1] =  4.9818874042678401e+06;
  domega_dot_reg_drhos[3][2] =  6.2934541598746339e+06;
  domega_dot_reg_drhos[3][3] = -7.3295923372729849e+03;
  domega_dot_reg_drhos[3][4] =  1.3153337903698755e+06;

  domega_dot_reg_drhos[4][0] =  4.7153530808281197e+01;
  domega_dot_reg_drhos[4][1] =  9.3437294776995126e+06;
  domega_dot_reg_drhos[4][2] =  6.8826657587473867e+06;
  domega_dot_reg_drhos[4][3] =  6.7211511181268143e+03;
  domega_dot_reg_drhos[4][4] = -2.4671202548241317e+06;

  for( unsigned int s = 0; s < n_species; s++)
    {
      for( unsigned int t = 0; t < n_species; t++)
        {
          const Scalar rel_error = abs( (domega_dot_drho_s[s][t] - domega_dot_reg_drhos[s][t])/domega_dot_reg_drhos[s][t]);
          if( rel_error > tol )
            {
              return_flag = 1;
            }
        }
    }

  // Print out pretty message if there was a problem.
  if( return_flag == 1 )
    {
      std::cerr << "Error: Mismatch between compute mass source terms and regression values." << std::endl;
      for( unsigned int s = 0; s < n_species; s++)
	{
	  std::cout << std::scientific << std::setprecision(16)
		    << "omega_dot(" << chem_mixture.chemical_species()[s]->species() << ") = " << omega_dot[s]
		    << ", omega_dot_reg(" << chem_mixture.chemical_species()[s]->species() << ") = "
                    << omega_dot_reg[s] << std::endl << std::endl;
	}

      for( unsigned int s = 0; s < n_species; s++)
	{
	  std::cout << std::scientific << std::setprecision(16)
		    << "domega_dot_dT(" << chem_mixture.chemical_species()[s]->species() << ") = " << domega_dot_dT[s]
		    << ", domega_dot_reg_dT(" << chem_mixture.chemical_species()[s]->species() << ") = "
                    << domega_dot_reg_dT[s] << std::endl << std::endl;
	}

      for( unsigned int s = 0; s < n_species; s++)
	{
          for( unsigned int t = 0; t < n_species; t++)
            {
              std::cout << std::scientific << std::setprecision(16)
                        << "domega_dot_drho_s("
                        << chem_mixture.chemical_species()[s]->species()
                        << ", " << chem_mixture.chemical_species()[t]->species()
                        << ") = " << domega_dot_drho_s[s][t]
                        << ", domega_dot_reg_dT("
                        << chem_mixture.chemical_species()[s]->species()
                        << ", " << chem_mixture.chemical_species()[t]->species()
                        << ") = " << domega_dot_reg_drhos[s][t] << std::endl << std::endl;
            }
	}

    }

  return return_flag;
}

int main(int argc, char* argv[])
{
  // Check command line count.
  if( argc < 2 )
    {
      // TODO: Need more consistent error handling.
      std::cerr << "Error: Must specify reaction set XML input file." << std::endl;
      antioch_error();
    }

  return (tester<float>(std::string(argv[1])) ||
          tester<double>(std::string(argv[1])) /*||
          tester<long double>(std::string(argv[1])) || */
          );
}
<commit_msg>Test both methods omega_dot output<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// Antioch - A Gas Dynamics Thermochemistry Library
//
// Copyright (C) 2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-
//
// $Id$
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

// C++
#include <limits>
#include <string>
#include <vector>

// Antioch
#include "antioch/vector_utils.h"

#include "antioch/antioch_asserts.h"
#include "antioch/chemical_species.h"
#include "antioch/chemical_mixture.h"
#include "antioch/reaction_set.h"
#include "antioch/read_reaction_set_data_xml.h"
#include "antioch/cea_thermo.h"
#include "antioch/kinetics_evaluator.h"

template <typename Scalar>
int tester(const std::string& input_name)
{
  using std::abs;

  std::vector<std::string> species_str_list;
  const unsigned int n_species = 5;
  species_str_list.reserve(n_species);
  species_str_list.push_back( "N2" );
  species_str_list.push_back( "O2" );
  species_str_list.push_back( "N" );
  species_str_list.push_back( "O" );
  species_str_list.push_back( "NO" );

  Antioch::ChemicalMixture<Scalar> chem_mixture( species_str_list );
  Antioch::ReactionSet<Scalar> reaction_set( chem_mixture );
  Antioch::CEAThermodynamics<Scalar> thermo( chem_mixture );

  Antioch::read_reaction_set_data_xml<Scalar>( input_name, true, reaction_set );

  const Scalar T = 1500.0;
  const Scalar P = 1.0e5;

  // Mass fractions
  std::vector<Scalar> Y(n_species,0.2);

  const Scalar R_mix = chem_mixture.R(Y);

  const Scalar rho = P/(R_mix*T);

  std::vector<Scalar> molar_densities(n_species,0.0);
  chem_mixture.molar_densities(rho,Y,molar_densities);

  std::vector<Scalar> h_RT_minus_s_R(n_species);
  std::vector<Scalar> dh_RT_minus_s_R_dT(n_species);

  typedef typename Antioch::CEAThermodynamics<Scalar>::template Cache<Scalar> Cache;
  thermo.h_RT_minus_s_R(Cache(T),h_RT_minus_s_R);
  thermo.dh_RT_minus_s_R_dT(Cache(T),dh_RT_minus_s_R_dT);

  Antioch::KineticsEvaluator<Scalar> kinetics( reaction_set, 0 );

  std::vector<Scalar> omega_dot(n_species);
  std::vector<Scalar> omega_dot_2(n_species);
  std::vector<Scalar> domega_dot_dT(n_species);

  std::vector<std::vector<Scalar> > domega_dot_drho_s(n_species);
  for( unsigned int s = 0; s < n_species; s++ )
    {
      domega_dot_drho_s[s].resize(n_species);
    }

  kinetics.compute_mass_sources( T, rho, R_mix, Y, molar_densities, h_RT_minus_s_R, omega_dot );

  kinetics.compute_mass_sources_and_derivs( T, rho, R_mix, Y, molar_densities, h_RT_minus_s_R, dh_RT_minus_s_R_dT,
                                            omega_dot_2, domega_dot_dT, domega_dot_drho_s );

  for( unsigned int s = 0; s < n_species; s++)
    {
      std::cout << std::scientific << std::setprecision(16)
		<< "omega_dot(" << chem_mixture.chemical_species()[s]->species() << ") = "
		<< omega_dot[s] << std::endl;
    }

  for( unsigned int s = 0; s < n_species; s++)
    {
      std::cout << std::scientific << std::setprecision(16)
                << "domega_dot_dT(" << chem_mixture.chemical_species()[s]->species() << ") = "
                << domega_dot_dT[s] << std::endl;
    }

  for( unsigned int s = 0; s < n_species; s++)
    {
      for( unsigned int t = 0; t < n_species; t++)
        {
          std::cout << std::scientific << std::setprecision(16)
                    << "domega_dot_drho_s(" << chem_mixture.chemical_species()[s]->species()
                    << ", " << chem_mixture.chemical_species()[t]->species() << ") = "
                    << domega_dot_drho_s[s][t] << std::endl;
        }
    }

  int return_flag = 0;

  const Scalar tol = std::numeric_limits<Scalar>::epsilon() * 100;

  // Regression values for omega_dot
  std::vector<Scalar> omega_dot_reg(n_species);
  omega_dot_reg[0] =  7.9004530802650654e+04;
  omega_dot_reg[1] = -3.4113853617637843e+05;
  omega_dot_reg[2] = -1.8898881857838202e+05;
  omega_dot_reg[3] =  2.1551399274321867e+05;
  omega_dot_reg[4] =  2.3560883120889112e+05;

  for( unsigned int s = 0; s < n_species; s++)
    {
      const Scalar rel_error = abs( (omega_dot[s] - omega_dot_reg[s])/omega_dot_reg[s]);
      if( rel_error > tol )
        {
          return_flag = 1;
        }
    }

  for( unsigned int s = 0; s < n_species; s++)
    {
      const Scalar rel_error = abs( (omega_dot_2[s] - omega_dot_reg[s])/omega_dot_reg[s]);
      if( rel_error > tol )
        {
          return_flag = 1;
        }
    }

  // Regression values for domega_dot_dT
  std::vector<Scalar> domega_dot_reg_dT(n_species);
  domega_dot_reg_dT[0] =  1.9573634782953712e+02;
  domega_dot_reg_dT[1] = -5.1996539987130484e+02;
  domega_dot_reg_dT[2] = -3.2528809609986996e+02;
  domega_dot_reg_dT[3] =  3.7199081589605311e+02;
  domega_dot_reg_dT[4] =  2.7752633224558451e+02;

  for( unsigned int s = 0; s < n_species; s++)
    {
      const Scalar rel_error = abs( (domega_dot_dT[s] - domega_dot_reg_dT[s])/domega_dot_reg_dT[s]);
      if( rel_error > tol )
        {
          return_flag = 1;
        }
    }

  // Regression values for domega_dot_drho_s
  std::vector<std::vector<Scalar> > domega_dot_reg_drhos(n_species);
  for( unsigned int s = 0; s < n_species; s++)
    {
      domega_dot_reg_drhos[s].resize(n_species);
    }

  domega_dot_reg_drhos[0][0] = 1.5777705018045012e+02;
  domega_dot_reg_drhos[0][1] = 1.3813389268698828e+02;
  domega_dot_reg_drhos[0][2] = 2.3115223534864103e+06;
  domega_dot_reg_drhos[0][3] = 1.1840007503997479e+03;
  domega_dot_reg_drhos[0][4] = 2.3043581130447080e+06;

  domega_dot_reg_drhos[1][0] =  7.1306539959731154e+01;
  domega_dot_reg_drhos[1][1] = -9.9638812606792040e+06;
  domega_dot_reg_drhos[1][2] = -9.9632306241494343e+06;
  domega_dot_reg_drhos[1][3] =  3.7459340498153397e+03;
  domega_dot_reg_drhos[1][4] =  1.1289308740617102e+02;

  domega_dot_reg_drhos[2][0] = -1.7978873571638729e+02;
  domega_dot_reg_drhos[2][1] = -4.3618737551808357e+06;
  domega_dot_reg_drhos[2][2] = -5.5244116479589976e+06;
  domega_dot_reg_drhos[2][3] = -4.3214935810689167e+03;
  domega_dot_reg_drhos[2][4] = -1.1526845416778582e+06;

  domega_dot_reg_drhos[3][0] = -9.6448385232075168e+01;
  domega_dot_reg_drhos[3][1] =  4.9818874042678401e+06;
  domega_dot_reg_drhos[3][2] =  6.2934541598746339e+06;
  domega_dot_reg_drhos[3][3] = -7.3295923372729849e+03;
  domega_dot_reg_drhos[3][4] =  1.3153337903698755e+06;

  domega_dot_reg_drhos[4][0] =  4.7153530808281197e+01;
  domega_dot_reg_drhos[4][1] =  9.3437294776995126e+06;
  domega_dot_reg_drhos[4][2] =  6.8826657587473867e+06;
  domega_dot_reg_drhos[4][3] =  6.7211511181268143e+03;
  domega_dot_reg_drhos[4][4] = -2.4671202548241317e+06;

  for( unsigned int s = 0; s < n_species; s++)
    {
      for( unsigned int t = 0; t < n_species; t++)
        {
          const Scalar rel_error = abs( (domega_dot_drho_s[s][t] - domega_dot_reg_drhos[s][t])/domega_dot_reg_drhos[s][t]);
          if( rel_error > tol )
            {
              return_flag = 1;
            }
        }
    }

  // Print out pretty message if there was a problem.
  if( return_flag == 1 )
    {
      std::cerr << "Error: Mismatch between compute mass source terms and regression values." << std::endl;
      for( unsigned int s = 0; s < n_species; s++)
	{
	  std::cout << std::scientific << std::setprecision(16)
		    << "omega_dot(" << chem_mixture.chemical_species()[s]->species() << ") = " << omega_dot[s]
		    << ", omega_dot_reg(" << chem_mixture.chemical_species()[s]->species() << ") = "
                    << omega_dot_reg[s] << std::endl << std::endl;
	}

      for( unsigned int s = 0; s < n_species; s++)
	{
	  std::cout << std::scientific << std::setprecision(16)
		    << "domega_dot_dT(" << chem_mixture.chemical_species()[s]->species() << ") = " << domega_dot_dT[s]
		    << ", domega_dot_reg_dT(" << chem_mixture.chemical_species()[s]->species() << ") = "
                    << domega_dot_reg_dT[s] << std::endl << std::endl;
	}

      for( unsigned int s = 0; s < n_species; s++)
	{
          for( unsigned int t = 0; t < n_species; t++)
            {
              std::cout << std::scientific << std::setprecision(16)
                        << "domega_dot_drho_s("
                        << chem_mixture.chemical_species()[s]->species()
                        << ", " << chem_mixture.chemical_species()[t]->species()
                        << ") = " << domega_dot_drho_s[s][t]
                        << ", domega_dot_reg_dT("
                        << chem_mixture.chemical_species()[s]->species()
                        << ", " << chem_mixture.chemical_species()[t]->species()
                        << ") = " << domega_dot_reg_drhos[s][t] << std::endl << std::endl;
            }
	}

    }

  return return_flag;
}

int main(int argc, char* argv[])
{
  // Check command line count.
  if( argc < 2 )
    {
      // TODO: Need more consistent error handling.
      std::cerr << "Error: Must specify reaction set XML input file." << std::endl;
      antioch_error();
    }

  return (tester<float>(std::string(argv[1])) ||
          tester<double>(std::string(argv[1])) /*||
          tester<long double>(std::string(argv[1])) || */
          );
}
<|endoftext|>


<commit_before>#include <graphlab/sdk/toolkit_function_macros.hpp>
#include <graphlab/sdk/gl_sgraph.hpp>
#include <iostream>
#include<fstream>

using namespace graphlab;
using namespace std;

int t_iteration;

void sum_shit(edge_triple& triple) {
    //triple.target["ait"] += triple.edge["aij"] * triple.source["ait"];

   	if (t_iteration % 2 != (int)triple.edge["parity"]) {
   		triple.target["ait"][t_iteration] += ((float)triple.source["ait"][t_iteration-1] * (float)triple.edge["aij"]);
   	}
    //triple.target["ait"][0] = 0;

}

gl_sgraph fp(gl_sgraph& g, std::vector<int> observation_seq) {

   // fill in Bi* for each vertex i
   // https://dato.com/products/create/sdk/docs/page_userguide_sframe.html
    //gl_sarray arr = g.vertices()["b"];
    FILE *f = fopen("test.txt", "w");
    /*
    for (std::vector<flexible_type> a: arr.range_iterator()) {
        for (float ai : a) {
            fprintf(f, "%f\n", ai);
        }
        fprintf(f, "\n");
    }
	*/
    //fclose(f);
    for (t_iteration = 1; t_iteration < observation_seq.size() + 1; t_iteration++) {
    	g = g.triple_apply(sum_shit, {"ait", "aij"});
    	fprintf(f, "%d\n", t_iteration);
    	fflush(f);
	}
	fclose(f);

	return g;
}

BEGIN_FUNCTION_REGISTRATION
REGISTER_FUNCTION(fp, "g", "observation_seq"); // provide named parameters
END_FUNCTION_REGISTRATION
<commit_msg>added initial code for gammas<commit_after>#include <graphlab/sdk/toolkit_function_macros.hpp>
#include <graphlab/sdk/gl_sgraph.hpp>
#include <iostream>
#include<fstream>
#include <assert.h>

using namespace graphlab;
using namespace std;

int t_iteration;

void sum_shit(edge_triple& triple) {
    //triple.target["ait"] += triple.edge["aij"] * triple.source["ait"];

   	if (t_iteration % 2 != (int)triple.edge["parity"]) {
   		triple.target["ait"][t_iteration] += ((float)triple.source["ait"][t_iteration-1] * (float)triple.edge["aij"]);
   	}
    //triple.target["ait"][0] = 0;

}

/*
 * stuff andy wrote
float vector_multiply(std::vector<flexible_type> a,
        std::vector<flexible_type> b) {

    assert(a.size() == b.size());
    std::vector<flexible_type> result;
    result.resize(b.size());

    for (int i = 0; i < a.size(); i++) {
        result[i] = a[i] * b[i];
    }

    return result
}

float vector_divide(std::vector<flexible_type> a,
        std::vector<flexible_type> b) {
    assert(a.size() == b.size());
    std::vector<flexible_type> result;
    result.resize(b.size());

    for (int i = 0; i < a.size(); i++) {
        result[i] = a[i] / b[i];
    }

    return result
}

void get_gammas(gl_sgraph& g) {

    verts = g.get_vertices();
    gammas = verts.apply([](const std::vector<flexible_type>& x) {
                                    return vector_multiply(x[0], x[1]);
                                    }, flex_type_enum:FLOAT);
    // column sums
    //gammas_normalizer =
}

*/

gl_sgraph fp(gl_sgraph& g, std::vector<int> observation_seq) {

    // fill in Bi* for each vertex i
    // https://dato.com/products/create/sdk/docs/page_userguide_sframe.html
    //gl_sarray arr = g.vertices()["b"];
    FILE *f = fopen("test.txt", "w");
    /*
    for (std::vector<flexible_type> a: arr.range_iterator()) {
        for (float ai : a) {
            fprintf(f, "%f\n", ai);
        }
        fprintf(f, "\n");
    }
	*/
    //fclose(f);
    for (t_iteration = 1; t_iteration < observation_seq.size() + 1; t_iteration++) {
    	g = g.triple_apply(sum_shit, {"ait", "aij"});
    	fprintf(f, "%d\n", t_iteration);
    	fflush(f);
	}
	fclose(f);

	return g;
}

BEGIN_FUNCTION_REGISTRATION
REGISTER_FUNCTION(fp, "g", "observation_seq"); // provide named parameters
END_FUNCTION_REGISTRATION
<|endoftext|>


<commit_before>#ifndef ESMREADER_HPP
#define ESMREADER_HPP

#include "Config.hpp"

class EsmReader : public Tools
{
public:
    void readFile(std::string path);

    bool getStatus() { return status; }
    std::string getName() { return name; }
    std::string getNamePrefix() { return name_prefix; }
    std::string getNameSuffix() { return name_suffix; }

    std::vector<std::string> const& getRecColl() const { return rec_coll; }

    void setRec(size_t i);
    void setRecContent(std::string content) { *rec = content; }
    std::string getRecContent() { return *rec; }

    void setUnique(std::string id, bool erase_null = true);
    bool setFriendly(std::string id, bool erase_null = true, bool next = false);
    void setDump();

    std::string getRecId() { return rec_id; }

    std::string getUnique() { return unique_text; }
    std::string getUniqueId() { return unique_id; }
    bool getUniqueStatus() { return unique_status; }

    std::string getFriendly() { return friendly_text; }
    std::string getFriendlyId() { return friendly_id; }
    size_t getFriendlyPos() { return friendly_pos; }
    size_t getFriendlySize() { return friendly_size; }
    size_t getFriendlyCounter() { return friendly_counter; }
    bool getFriendlyStatus() { return friendly_status; }

    EsmReader();

private:
    void printStatus(std::string path);
    void setName(std::string path);
    void setRecColl(std::string &content);

    bool status = false;
    std::vector<std::string> rec_coll;

    std::string name;
    std::string name_prefix;
    std::string name_suffix;

    std::string *rec;

    size_t rec_size;
    std::string rec_id;

    std::string unique_id;
    std::string unique_text;
    bool unique_status = false;

    std::string friendly_id;
    std::string friendly_text;
    size_t friendly_pos;
    size_t friendly_size;
    size_t friendly_counter;
    bool friendly_status = false;
};

#endif
<commit_msg>remove unnecesary functionality<commit_after>#ifndef ESMREADER_HPP
#define ESMREADER_HPP

#include "Config.hpp"

class EsmReader : public Tools
{
public:
    void readFile(std::string path);

    bool getStatus() { return status; }
    std::string getName() { return name; }
    std::string getNamePrefix() { return name_prefix; }
    std::string getNameSuffix() { return name_suffix; }

    std::vector<std::string> const& getRecColl() const { return rec_coll; }

    void setRec(size_t i);
    void setRecContent(std::string content) { *rec = content; }
    std::string getRecContent() { return *rec; }

    void setUnique(std::string id, bool erase_null = true);
    bool setFriendly(std::string id, bool erase_null = true, bool next = false);

    std::string getRecId() { return rec_id; }

    std::string getUnique() { return unique_text; }
    std::string getUniqueId() { return unique_id; }
    bool getUniqueStatus() { return unique_status; }

    std::string getFriendly() { return friendly_text; }
    std::string getFriendlyId() { return friendly_id; }
    size_t getFriendlyPos() { return friendly_pos; }
    size_t getFriendlySize() { return friendly_size; }
    size_t getFriendlyCounter() { return friendly_counter; }
    bool getFriendlyStatus() { return friendly_status; }

    EsmReader();

private:
    void printStatus(std::string path);
    void setName(std::string path);
    void setRecColl(std::string &content);

    bool status = false;
    std::vector<std::string> rec_coll;

    std::string name;
    std::string name_prefix;
    std::string name_suffix;

    std::string *rec;

    size_t rec_size;
    std::string rec_id;

    std::string unique_id;
    std::string unique_text;
    bool unique_status = false;

    std::string friendly_id;
    std::string friendly_text;
    size_t friendly_pos;
    size_t friendly_size;
    size_t friendly_counter;
    bool friendly_status = false;
};

#endif
<|endoftext|>


<commit_before>/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Copyright (C) 2017 ScyllaDB
 */

#pragma once

#include <map>
#include <seastar/core/future.hh>
#include "reader_permit.hh"

using namespace seastar;

/// Specific semaphore for controlling reader concurrency
///
/// Use `make_permit()` to create a permit to track the resource consumption
/// of a specific read. The permit should be created before the read is even
/// started so it is available to track resource consumption from the start.
/// Reader concurrency is dual limited by count and memory.
/// The semaphore can be configured with the desired limits on
/// construction. New readers will only be admitted when there is both
/// enough count and memory units available. Readers are admitted in
/// FIFO order.
/// Semaphore's `name` must be provided in ctor and its only purpose is
/// to increase readability of exceptions: both timeout exceptions and
/// queue overflow exceptions (read below) include this `name` in messages.
/// It's also possible to specify the maximum allowed number of waiting
/// readers by the `max_queue_length` constructor parameter. When the
/// number of waiting readers becomes equal or greater than
/// `max_queue_length` (upon calling `wait_admission()`) an exception of
/// type `std::runtime_error` is thrown. Optionally, some additional
/// code can be executed just before throwing (`prethrow_action`
/// constructor parameter).
class reader_concurrency_semaphore {
public:
    using resources = reader_resources;

    friend class reader_permit;

    class inactive_read {
    public:
        virtual void evict() = 0;
        virtual ~inactive_read() = default;
    };

    class inactive_read_handle {
        reader_concurrency_semaphore* _sem = nullptr;
        uint64_t _id = 0;

        friend class reader_concurrency_semaphore;

        explicit inactive_read_handle(reader_concurrency_semaphore& sem, uint64_t id)
            : _sem(&sem), _id(id) {
        }
    public:
        inactive_read_handle() = default;
        inactive_read_handle(inactive_read_handle&& o) : _sem(std::exchange(o._sem, nullptr)), _id(std::exchange(o._id, 0)) {
        }
        inactive_read_handle& operator=(inactive_read_handle&& o) {
            _sem = std::exchange(o._sem, nullptr);
            _id = std::exchange(o._id, 0);
            return *this;
        }
        explicit operator bool() const {
            return bool(_id);
        }
    };

    struct stats {
        // The number of inactive reads evicted to free up permits.
        uint64_t permit_based_evictions = 0;
        // The number of inactive reads currently registered.
        uint64_t inactive_reads = 0;
    };

private:
    struct entry {
        promise<reader_permit::resource_units> pr;
        resources res;
        entry(promise<reader_permit::resource_units>&& pr, resources r) : pr(std::move(pr)), res(r) {}
    };

    class expiry_handler {
        sstring _semaphore_name;
    public:
        explicit expiry_handler(sstring semaphore_name)
            : _semaphore_name(std::move(semaphore_name)) {}
        void operator()(entry& e) noexcept {
            e.pr.set_exception(named_semaphore_timed_out(_semaphore_name));
        }
    };

private:
    const resources _initial_resources;
    resources _resources;

    expiring_fifo<entry, expiry_handler, db::timeout_clock> _wait_list;

    sstring _name;
    size_t _max_queue_length = std::numeric_limits<size_t>::max();
    std::function<void()> _prethrow_action;
    uint64_t _next_id = 1;
    std::map<uint64_t, std::unique_ptr<inactive_read>> _inactive_reads;
    stats _stats;

private:
    bool has_available_units(const resources& r) const {
        return bool(_resources) && _resources >= r;
    }

    bool may_proceed(const resources& r) const {
        return has_available_units(r) && _wait_list.empty();
    }

    future<reader_permit::resource_units> do_wait_admission(size_t memory, db::timeout_clock::time_point timeout);

public:
    struct no_limits { };

    reader_concurrency_semaphore(int count,
            ssize_t memory,
            sstring name,
            size_t max_queue_length = std::numeric_limits<size_t>::max(),
            std::function<void()> prethrow_action = nullptr)
        : _initial_resources(count, memory)
        , _resources(count, memory)
        , _wait_list(expiry_handler(name))
        , _name(std::move(name))
        , _max_queue_length(max_queue_length)
        , _prethrow_action(std::move(prethrow_action)) {}

    /// Create a semaphore with practically unlimited count and memory.
    ///
    /// And conversely, no queue limit either.
    explicit reader_concurrency_semaphore(no_limits, sstring name = "unlimited reader_concurrency_semaphore")
        : reader_concurrency_semaphore(
                std::numeric_limits<int>::max(),
                std::numeric_limits<ssize_t>::max(),
                std::move(name)) {}

    ~reader_concurrency_semaphore();

    reader_concurrency_semaphore(const reader_concurrency_semaphore&) = delete;
    reader_concurrency_semaphore& operator=(const reader_concurrency_semaphore&) = delete;

    reader_concurrency_semaphore(reader_concurrency_semaphore&&) = delete;
    reader_concurrency_semaphore& operator=(reader_concurrency_semaphore&&) = delete;

    /// Returns the name of the semaphore
    ///
    /// If the semaphore has no name, "unnamed reader concurrency semaphore" is returned.
    std::string_view name() const {
        return _name.empty() ? "unnamed reader concurrency semaphore" : std::string_view(_name);
    }

    /// Register an inactive read.
    ///
    /// The semaphore will evict this read when there is a shortage of
    /// permits. This might be immediate, during this register call.
    /// Clients can use the returned handle to unregister the read, when it
    /// stops being inactive and hence evictable.
    ///
    /// An inactive read is an object implementing the `inactive_read`
    /// interface.
    /// The semaphore takes ownership of the created object and destroys it if
    /// it is evicted.
    inactive_read_handle register_inactive_read(std::unique_ptr<inactive_read> ir);

    /// Unregister the previously registered inactive read.
    ///
    /// If the read was not evicted, the inactive read object, passed in to the
    /// register call, will be returned. Otherwise a nullptr is returned.
    std::unique_ptr<inactive_read> unregister_inactive_read(inactive_read_handle irh);

    /// Try to evict an inactive read.
    ///
    /// Return true if an inactive read was evicted and false otherwise
    /// (if there was no reader to evict).
    bool try_evict_one_inactive_read();

    void clear_inactive_reads() {
        _inactive_reads.clear();
    }

    const stats& get_stats() const {
        return _stats;
    }

    reader_permit make_permit();

    const resources initial_resources() const {
        return _initial_resources;
    }

    const resources available_resources() const {
        return _resources;
    }

    void consume(resources r) {
        _resources -= r;
    }

    void signal(const resources& r) noexcept;

    size_t waiters() const {
        return _wait_list.size();
    }

    void broken(std::exception_ptr ex);
};
<commit_msg>reader_concurrency_semaphore: add non-const stats accessor<commit_after>/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Copyright (C) 2017 ScyllaDB
 */

#pragma once

#include <map>
#include <seastar/core/future.hh>
#include "reader_permit.hh"

using namespace seastar;

/// Specific semaphore for controlling reader concurrency
///
/// Use `make_permit()` to create a permit to track the resource consumption
/// of a specific read. The permit should be created before the read is even
/// started so it is available to track resource consumption from the start.
/// Reader concurrency is dual limited by count and memory.
/// The semaphore can be configured with the desired limits on
/// construction. New readers will only be admitted when there is both
/// enough count and memory units available. Readers are admitted in
/// FIFO order.
/// Semaphore's `name` must be provided in ctor and its only purpose is
/// to increase readability of exceptions: both timeout exceptions and
/// queue overflow exceptions (read below) include this `name` in messages.
/// It's also possible to specify the maximum allowed number of waiting
/// readers by the `max_queue_length` constructor parameter. When the
/// number of waiting readers becomes equal or greater than
/// `max_queue_length` (upon calling `wait_admission()`) an exception of
/// type `std::runtime_error` is thrown. Optionally, some additional
/// code can be executed just before throwing (`prethrow_action`
/// constructor parameter).
class reader_concurrency_semaphore {
public:
    using resources = reader_resources;

    friend class reader_permit;

    class inactive_read {
    public:
        virtual void evict() = 0;
        virtual ~inactive_read() = default;
    };

    class inactive_read_handle {
        reader_concurrency_semaphore* _sem = nullptr;
        uint64_t _id = 0;

        friend class reader_concurrency_semaphore;

        explicit inactive_read_handle(reader_concurrency_semaphore& sem, uint64_t id)
            : _sem(&sem), _id(id) {
        }
    public:
        inactive_read_handle() = default;
        inactive_read_handle(inactive_read_handle&& o) : _sem(std::exchange(o._sem, nullptr)), _id(std::exchange(o._id, 0)) {
        }
        inactive_read_handle& operator=(inactive_read_handle&& o) {
            _sem = std::exchange(o._sem, nullptr);
            _id = std::exchange(o._id, 0);
            return *this;
        }
        explicit operator bool() const {
            return bool(_id);
        }
    };

    struct stats {
        // The number of inactive reads evicted to free up permits.
        uint64_t permit_based_evictions = 0;
        // The number of inactive reads currently registered.
        uint64_t inactive_reads = 0;
    };

private:
    struct entry {
        promise<reader_permit::resource_units> pr;
        resources res;
        entry(promise<reader_permit::resource_units>&& pr, resources r) : pr(std::move(pr)), res(r) {}
    };

    class expiry_handler {
        sstring _semaphore_name;
    public:
        explicit expiry_handler(sstring semaphore_name)
            : _semaphore_name(std::move(semaphore_name)) {}
        void operator()(entry& e) noexcept {
            e.pr.set_exception(named_semaphore_timed_out(_semaphore_name));
        }
    };

private:
    const resources _initial_resources;
    resources _resources;

    expiring_fifo<entry, expiry_handler, db::timeout_clock> _wait_list;

    sstring _name;
    size_t _max_queue_length = std::numeric_limits<size_t>::max();
    std::function<void()> _prethrow_action;
    uint64_t _next_id = 1;
    std::map<uint64_t, std::unique_ptr<inactive_read>> _inactive_reads;
    stats _stats;

private:
    bool has_available_units(const resources& r) const {
        return bool(_resources) && _resources >= r;
    }

    bool may_proceed(const resources& r) const {
        return has_available_units(r) && _wait_list.empty();
    }

    future<reader_permit::resource_units> do_wait_admission(size_t memory, db::timeout_clock::time_point timeout);

public:
    struct no_limits { };

    reader_concurrency_semaphore(int count,
            ssize_t memory,
            sstring name,
            size_t max_queue_length = std::numeric_limits<size_t>::max(),
            std::function<void()> prethrow_action = nullptr)
        : _initial_resources(count, memory)
        , _resources(count, memory)
        , _wait_list(expiry_handler(name))
        , _name(std::move(name))
        , _max_queue_length(max_queue_length)
        , _prethrow_action(std::move(prethrow_action)) {}

    /// Create a semaphore with practically unlimited count and memory.
    ///
    /// And conversely, no queue limit either.
    explicit reader_concurrency_semaphore(no_limits, sstring name = "unlimited reader_concurrency_semaphore")
        : reader_concurrency_semaphore(
                std::numeric_limits<int>::max(),
                std::numeric_limits<ssize_t>::max(),
                std::move(name)) {}

    ~reader_concurrency_semaphore();

    reader_concurrency_semaphore(const reader_concurrency_semaphore&) = delete;
    reader_concurrency_semaphore& operator=(const reader_concurrency_semaphore&) = delete;

    reader_concurrency_semaphore(reader_concurrency_semaphore&&) = delete;
    reader_concurrency_semaphore& operator=(reader_concurrency_semaphore&&) = delete;

    /// Returns the name of the semaphore
    ///
    /// If the semaphore has no name, "unnamed reader concurrency semaphore" is returned.
    std::string_view name() const {
        return _name.empty() ? "unnamed reader concurrency semaphore" : std::string_view(_name);
    }

    /// Register an inactive read.
    ///
    /// The semaphore will evict this read when there is a shortage of
    /// permits. This might be immediate, during this register call.
    /// Clients can use the returned handle to unregister the read, when it
    /// stops being inactive and hence evictable.
    ///
    /// An inactive read is an object implementing the `inactive_read`
    /// interface.
    /// The semaphore takes ownership of the created object and destroys it if
    /// it is evicted.
    inactive_read_handle register_inactive_read(std::unique_ptr<inactive_read> ir);

    /// Unregister the previously registered inactive read.
    ///
    /// If the read was not evicted, the inactive read object, passed in to the
    /// register call, will be returned. Otherwise a nullptr is returned.
    std::unique_ptr<inactive_read> unregister_inactive_read(inactive_read_handle irh);

    /// Try to evict an inactive read.
    ///
    /// Return true if an inactive read was evicted and false otherwise
    /// (if there was no reader to evict).
    bool try_evict_one_inactive_read();

    void clear_inactive_reads() {
        _inactive_reads.clear();
    }

    const stats& get_stats() const {
        return _stats;
    }

    stats& get_stats() {
        return _stats;
    }

    reader_permit make_permit();

    const resources initial_resources() const {
        return _initial_resources;
    }

    const resources available_resources() const {
        return _resources;
    }

    void consume(resources r) {
        _resources -= r;
    }

    void signal(const resources& r) noexcept;

    size_t waiters() const {
        return _wait_list.size();
    }

    void broken(std::exception_ptr ex);
};
<|endoftext|>


<commit_before>// Copyright (c) 2017 Daniel Cooke
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

#include <vector>
#include <deque>
#include <string>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <random>
#include <utility>
#include <cassert>
#include <iostream>

#include "mappable/mappable_fwd.hpp"

using namespace mappable;

// Some types used in this example

// Mappable provdes two fundamental region types which all Mappable types must use.
//
// ContigRegion is the simpler of the two; it is just a start and end co-ordinate. Use this
// when you know, or don't need to know the contig mapping.
//
// GenomicRegion is a contig name + a ContigRegion, and thus defines a complete genomic mapping.
// It therefore uses a few more bytes compared to ContigRegion.
//
// Note both ContigRegion and GenomicRegion use half open intervals [begin, end).
//
// All Mappable methods, algorithms, and containers work the same with both ContigRegion and GenomicRegion,
// but you can't directly compare one with the other, which means you can't mix the two types in the same
// collection.

//
// Example using ContigRegion
//
struct Read : public Mappable<Read>
{
    ContigRegion region;
    unsigned quality;
    const ContigRegion& mapped_region() const noexcept { return region; } // required for Mappable
    Read(unsigned begin, unsigned end, unsigned quality) : region {begin, end}, quality {quality} {}
};

std::ostream& operator<<(std::ostream& os, const Read& read)
{
    os << "(" << read.region << " " << read.quality << ")";
    return os;
}

using MappingQualitySet = MappableFlatMultiSet<Read>;

//
// Example using GenomicRegion
//
struct Allele : public Mappable<Allele>, Comparable<Allele>
{
    GenomicRegion region;
    std::string sequence;
    const GenomicRegion& mapped_region() const noexcept { return region; } // required for Mappable
    template <typename R, typename S> Allele(R&& region, S&& sequence)
    : region {std::forward<R>(region)}, sequence {std::forward<S>(sequence)} {}
};

// We define operators == and < for Allele as we want to make sure alleles with
// different sequences are distinct; the default comparitors provided by Mappable
// only compare regions.
// Note is important the any user defined operator< comparitor for Mappable types
// satisfies the properties of Mappables default operator<. That is, any Mappable type must
// first sort by the types region; only objects deemed equivilant by the default operator<
// can be futher sorted.
bool operator==(const Allele& lhs, const Allele& rhs) noexcept
{
    return lhs.region == rhs.region && lhs.sequence == rhs.sequence;
}
bool operator<(const Allele& lhs, const Allele& rhs) noexcept
{
    return lhs.region == rhs.region ? lhs.sequence < rhs.sequence : lhs.region < rhs.region;
}

std::ostream& operator<<(std::ostream& os, const Allele& allele)
{
    os << "{" << allele.region << " " << allele.sequence << "}";
    return os;
}

using AlleleSet = MappableFlatSet<Allele>;

struct Genotype : public Mappable<Genotype>
{
    Allele first, second;
    const GenomicRegion& mapped_region() const noexcept { return first.mapped_region(); } // required for Mappable
    template <typename A1, typename A2> Genotype(A1&& first, A2&& second)
    : first {std::forward<A1>(first)}, second {std::forward<A2>(second)} {}
    template <typename R, typename S1, typename S2>
    Genotype(R&& region, S1&& sequence1, S2&& sequence2)
    : first {region, std::forward<S1>(sequence1)}
    , second {std::forward<R>(region), std::forward<S2>(sequence2)}
    {}
};

std::ostream& operator<<(std::ostream& os, const Genotype& genotype)
{
    os << "[" << genotype.first << " " << genotype.second << "]";
    return os;
}

using AlleleReference = MappableReferenceWrapper<Allele>;

std::ostream& operator<<(std::ostream& os, const AlleleReference& allele)
{
    os << allele.get();
    return os;
}

// Some utility print methods

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
    std::copy(std::cbegin(v), std::cend(v), std::ostream_iterator<T> {os, " "});
    return os;
}

template <typename It>
std::ostream& operator<<(std::ostream& os, const OverlapRange<It>& range)
{
    using T = typename std::iterator_traits<It>::value_type;
    std::copy(std::cbegin(range), std::cend(range), std::ostream_iterator<T> {os, " "});
    return os;
}

template <typename It>
std::ostream& operator<<(std::ostream& os, const ContainedRange<It>& range)
{
    using T = typename std::iterator_traits<It>::value_type;
    std::copy(std::cbegin(range), std::cend(range), std::ostream_iterator<T> {os, " "});
    return os;
}

//
// This example shows basic usage with standard C++ containers
//
void std_container_example()
{
    using std::cbegin; using std::cend;
    std::cout << "Running std_container_example..." << std::endl;

    const ContigRegion r1 {0, 2}, r2 {1, 2}, r3 {1, 3}, r4 {2, 5}, r5 {3, 4}, r6 {4, 5};

    // Mappable works with standard containers
    const std::vector<ContigRegion> regions_vector {r1, r2, r3, r4, r5, r6};
    const std::deque<ContigRegion> regions_deque {r1, r2, r3, r4, r5, r6};

    // Mappable algorithms require sorted ranges
    assert(std::is_sorted(cbegin(regions_vector), cend(regions_vector)));
    assert(std::is_sorted(cbegin(regions_deque), cend(regions_deque)));

    std::cout << "regions_vector: " << regions_vector << std::endl;
    std::cout << "regions_deque: " << regions_vector << std::endl;

    const ContigRegion test {2, 4};

    const auto overlapped_vector = overlap_range(regions_vector, test);
    std::cout << "There are " << count_overlapped(regions_vector, test)
              << " regions in regions_vector overlapped with " << test << ": "
              << overlapped_vector << std::endl;
    const auto overlapped_deque = overlap_range(regions_deque, test);
    std::cout << "There are " << count_overlapped(regions_deque, test)
              << " regions in regions_deque overlapped with " << test << ": "
              << overlapped_deque << std::endl;

    // Note: You wouldn't use count_overlapped like this if you already had
    // the result for overlap_range; just call size(overlapped_vector) instead.
}

void mappable_multiset_example()
{
    std::cout << "Running mappable_set_example..." << std::endl;

    constexpr std::size_t num_reads {100'000};
    constexpr unsigned read_size {150};
    constexpr ContigRegion::Size contig_size {2'000'000};

    static std::default_random_engine gen {};
    std::uniform_int_distribution<ContigRegion::Size> position_dist {0, contig_size};
    std::uniform_int_distribution<unsigned> quality_dist {0, 100};

    MappingQualitySet reads {};

    // First let's fill the container with some randomly generated data.
    // We don't need to worry about sorting as MappableFlatMultiSet will
    // handle this.
    std::cout << "Inserting " << num_reads << " randomly generated 'reads' into the MappableFlatMultiSet" << std::endl;
    reads.reserve(num_reads);
    std::generate_n(std::inserter(reads, std::begin(reads)), num_reads, [&] () -> Read {
        auto begin = position_dist(gen);
        auto quality = quality_dist(gen);
        return {begin, std::min(begin + read_size, contig_size), quality};
    });
    // Note this is a very inefficient way to input data into a MappableFlatMultiSet!
    // A much better way is to insert pre-sorted data.

    // We can now query the MappableFlatMultiSet using any mappable algorithm.
    const ContigRegion test_region {contig_size / 2 - contig_size / 4, contig_size / 2 + contig_size / 4};
    std::cout << "There are " << count_overlapped(reads, test_region) << " reads overlapping with " << test_region << std::endl;
    std::cout << "There are " << count_contained(reads, test_region) << " reads contained within " << test_region << std::endl;

    // Let's do something a bit more interesting; calculate the average read quality
    // of reads contained in a region.
    const auto contained = contained_range(reads, test_region);
    const auto quality_sum = std::accumulate(std::cbegin(contained), std::cend(contained), 0.0,
                                             [] (auto curr, const auto& read) { return curr + read.quality; });
    const auto mean_quality = quality_sum / size(contained);
    std::cout << "The mean quality of reads contained in " << test_region << " is " << mean_quality << std::endl;

    // Which positions on are contig have read coverage?
    const auto covered_regions = extract_covered_regions(reads);
    const auto covered_length = sum_region_sizes(covered_regions);
    const auto covered_fraction = 100 * static_cast<double>(covered_length) / contig_size;
    std::cout << "The generated reads covered " << covered_fraction << "% of the contig: "
              << covered_regions << std::endl;

    // We can also easily get any 'intervening' regions between the covered regions.
    const auto intervening_regions = extract_intervening_regions(covered_regions, ContigRegion {0, contig_size});
    const auto intervening_length = sum_region_sizes(intervening_regions);
    std::cout << "covered_length + intervening_length = " << covered_length + intervening_length << std::endl;

    // We can also efficiently look at the coverage in a region
    const auto depths = calculate_positional_coverage(reads, reads[num_reads / 2]);
    std::cout << "The depth of each position in the region " << mapped_region(reads[num_reads / 2])
              << " is " << depths << std::endl;

    // It's easy to remove items from a MappableFlatMultiSet...
    reads.erase_overlapped(test_region);
    std::cout << "After removing reads overlapped with " << test_region
              << " there are " << reads.size() << " reads remaining" << std::endl;
}

void mappable_set_example()
{
    std::cout << "Running mappable_multiset_example..." << std::endl;

    // MappableFlatSet is similar to MappableFlatMultiSet, but duplicates are not allowed.
    // There is also no reserve method for MappableFlatSet.

    AlleleSet alleles {};
    alleles.emplace(GenomicRegion {"X", 100, 101}, "A");
    alleles.emplace(GenomicRegion {"X", 101, 102}, "C");
    alleles.emplace(GenomicRegion {"X", 101, 102}, "AC");
    assert(alleles.size() == 3);
    alleles.emplace(GenomicRegion {"X", 100, 101}, "A");
    assert(alleles.size() == 3);
}

void complex_usage_example()
{
    std::cout << "Running complex_usage_example..." << std::endl;

    // One of the most powerful of the Mappable library is the ability to mix
    // different Mappable types (assuming same underlying region type - see intro).
    // For example, we can suppose we have some genotypes

    const std::vector<Genotype> genotypes {
        Genotype {GenomicRegion {"X", 0, 2}, "CC", "CC"},
        Genotype {GenomicRegion {"X", 2, 3}, "A", "C"},
        Genotype {GenomicRegion {"X", 3, 4}, "G", "T"},
        Genotype {GenomicRegion {"X", 4, 9}, "ACGT", ""},
        Genotype {GenomicRegion {"X", 9, 10}, "A", "A"}
    };

    assert(std::is_sorted(std::cbegin(genotypes), std::cend(genotypes)));

    // What alleles are present?
    AlleleSet alleles {};
    for (const auto& genotype : genotypes) {
        alleles.insert(genotype.first);
        alleles.insert(genotype.second);
    }

    // Which alleles are overlapped with each genotype?
    for (const auto& genotype : genotypes) {
        auto overlapped = overlap_range(alleles, genotype);
        std::cout << genotype << ": " << overlapped << std::endl;
    }
    // Note we didn't need to pass a region to overlap_range, we just passed
    // the genotype directly. Because both Allele and Genotype are mappable,
    // we can easily compare them in region space.
}

void mappable_reference_wrapper_example()
{
    std::cout << "Running complex_usage_example..." << std::endl;

    // Sometimes you will want to store a collection of references to Mappable objects.
    // As standard C++ solutions to this (e.g. pointers or std::reference_wrapper) are not
    // themselves Mappable, you wouldn't be able to use any mappable algorithms on this collection.
    // MappableReferenceWrapper provides a solution to this.

    std::vector<Allele> alleles {};
    alleles.emplace_back(GenomicRegion {"X", 100, 101}, "A");
    alleles.emplace_back(GenomicRegion {"X", 101, 104}, "GTC");
    alleles.emplace_back(GenomicRegion {"X", 102, 103}, "T");

    std::cout << "alleles: " << alleles << std::endl;

    std::vector<AlleleReference> allele_refs {};
    allele_refs.push_back(alleles[0]);
    allele_refs.push_back(alleles[2]);

    std::cout << "allele_refs: " << alleles << std::endl;

    assert(std::is_sorted(std::cbegin(allele_refs), std::cend(allele_refs)));

    std::cout << "There is " << count_overlapped(allele_refs, alleles[1])
              << " allele ref overlapped with " << alleles[1] << ": ";
    const auto overlapped = overlap_range(allele_refs, alleles[1]);
    std::cout << overlapped << std::endl;
}

int main()
{
    std_container_example();
    mappable_multiset_example();
    mappable_set_example();
    complex_usage_example();
    mappable_reference_wrapper_example();
}
<commit_msg>Improve example<commit_after>// Copyright (c) 2017 Daniel Cooke
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

#include <vector>
#include <deque>
#include <string>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <random>
#include <utility>
#include <cassert>
#include <iostream>

#include "mappable/mappable_fwd.hpp"

using namespace mappable;

// Some types used in this example

// Mappable provdes two fundamental region types which all Mappable types must use.
//
// ContigRegion is the simpler of the two; it is just a start and end co-ordinate. Use this
// when you know, or don't need to know the contig mapping.
//
// GenomicRegion is a contig name + a ContigRegion, and thus defines a complete genomic mapping.
// It therefore uses a few more bytes compared to ContigRegion.
//
// Note both ContigRegion and GenomicRegion use half open intervals [begin, end).
//
// All Mappable methods, algorithms, and containers work the same with both ContigRegion and GenomicRegion,
// but you can't directly compare one with the other, which means you can't mix the two types in the same
// collection.

//
// Example using ContigRegion
//
struct Read : public Mappable<Read>
{
    ContigRegion region;
    unsigned quality;
    const ContigRegion& mapped_region() const noexcept { return region; } // required for Mappable
    Read(unsigned begin, unsigned end, unsigned quality) : region {begin, end}, quality {quality} {}
};

std::ostream& operator<<(std::ostream& os, const Read& read)
{
    os << "(" << read.region << " " << read.quality << ")";
    return os;
}

using MappingQualitySet = MappableFlatMultiSet<Read>;

//
// Example using GenomicRegion
//
struct Allele : public Mappable<Allele>, Comparable<Allele>
{
    GenomicRegion region;
    std::string sequence;
    const GenomicRegion& mapped_region() const noexcept { return region; } // required for Mappable
    template <typename R, typename S> Allele(R&& region, S&& sequence)
    : region {std::forward<R>(region)}, sequence {std::forward<S>(sequence)} {}
};

// We define operators == and < for Allele as we want to make sure alleles with
// different sequences are distinct; the default comparitors provided by Mappable
// only compare regions.
// Note is important the any user defined operator< comparitor for Mappable types
// satisfies the properties of Mappables default operator<. That is, any Mappable type must
// first sort by the types region; only objects deemed equivilant by the default operator<
// can be futher sorted.
bool operator==(const Allele& lhs, const Allele& rhs) noexcept
{
    return lhs.region == rhs.region && lhs.sequence == rhs.sequence;
}
bool operator<(const Allele& lhs, const Allele& rhs) noexcept
{
    // Note the region must be the strongest ordering component to satisfy
    // Mappable requirements
    return lhs.region == rhs.region ? lhs.sequence < rhs.sequence : lhs.region < rhs.region;
}

std::ostream& operator<<(std::ostream& os, const Allele& allele)
{
    os << "{" << allele.region << " " << allele.sequence << "}";
    return os;
}

using AlleleSet = MappableFlatSet<Allele>;

struct Genotype : public Mappable<Genotype>
{
    Allele first, second;
    const GenomicRegion& mapped_region() const noexcept { return first.mapped_region(); } // required for Mappable
    template <typename A1, typename A2> Genotype(A1&& first, A2&& second)
    : first {std::forward<A1>(first)}, second {std::forward<A2>(second)} {}
    template <typename R, typename S1, typename S2>
    Genotype(R&& region, S1&& sequence1, S2&& sequence2)
    : first {region, std::forward<S1>(sequence1)}
    , second {std::forward<R>(region), std::forward<S2>(sequence2)}
    {}
};

std::ostream& operator<<(std::ostream& os, const Genotype& genotype)
{
    os << "[" << genotype.first << " " << genotype.second << "]";
    return os;
}

using AlleleReference = MappableReferenceWrapper<Allele>;

std::ostream& operator<<(std::ostream& os, const AlleleReference& allele)
{
    os << allele.get();
    return os;
}

// Some utility print methods

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
    std::copy(std::cbegin(v), std::cend(v), std::ostream_iterator<T> {os, " "});
    return os;
}

template <typename It>
std::ostream& operator<<(std::ostream& os, const OverlapRange<It>& range)
{
    using T = typename std::iterator_traits<It>::value_type;
    std::copy(std::cbegin(range), std::cend(range), std::ostream_iterator<T> {os, " "});
    return os;
}

template <typename It>
std::ostream& operator<<(std::ostream& os, const ContainedRange<It>& range)
{
    using T = typename std::iterator_traits<It>::value_type;
    std::copy(std::cbegin(range), std::cend(range), std::ostream_iterator<T> {os, " "});
    return os;
}

//
// This example shows basic usage with standard C++ containers
//
void std_container_example()
{
    using std::cbegin; using std::cend;
    std::cout << "Running std_container_example..." << std::endl;

    const ContigRegion r1 {0, 2}, r2 {1, 2}, r3 {1, 3}, r4 {2, 5}, r5 {3, 4}, r6 {4, 5};

    // Mappable works with standard containers
    const std::vector<ContigRegion> regions_vector {r1, r2, r3, r4, r5, r6};
    const std::deque<ContigRegion> regions_deque {r1, r2, r3, r4, r5, r6};

    // Mappable algorithms require sorted ranges
    assert(std::is_sorted(cbegin(regions_vector), cend(regions_vector)));
    assert(std::is_sorted(cbegin(regions_deque), cend(regions_deque)));

    std::cout << "regions_vector: " << regions_vector << std::endl;
    std::cout << "regions_deque: " << regions_vector << std::endl;

    const ContigRegion test {2, 4};

    const auto overlapped_vector = overlap_range(regions_vector, test);
    std::cout << "There are " << count_overlapped(regions_vector, test)
              << " regions in regions_vector overlapped with " << test << ": "
              << overlapped_vector << std::endl;
    const auto overlapped_deque = overlap_range(regions_deque, test);
    std::cout << "There are " << count_overlapped(regions_deque, test)
              << " regions in regions_deque overlapped with " << test << ": "
              << overlapped_deque << std::endl;

    // Note: You wouldn't use count_overlapped like this if you already had
    // the result for overlap_range; just call size(overlapped_vector) instead.
}

void mappable_multiset_example()
{
    std::cout << "Running mappable_set_example..." << std::endl;

    constexpr std::size_t num_reads {100'000};
    constexpr unsigned read_size {150};
    constexpr ContigRegion::Size contig_size {2'000'000};

    static std::default_random_engine gen {};
    std::uniform_int_distribution<ContigRegion::Size> position_dist {0, contig_size};
    std::uniform_int_distribution<unsigned> quality_dist {0, 100};

    MappingQualitySet reads {};

    const auto generate_random_read = [&] () -> Read {
        auto begin = position_dist(gen);
        auto quality = quality_dist(gen);
        return {begin, std::min(begin + read_size, contig_size), quality};
    };

    // First let's fill the container with some randomly generated data.
    // We don't need to worry about sorting as MappableFlatMultiSet will
    // handle this.
    std::cout << "Inserting " << num_reads << " randomly generated 'reads' into the MappableFlatMultiSet" << std::endl;
    reads.reserve(num_reads);
    std::generate_n(std::inserter(reads, std::begin(reads)), num_reads / 2, generate_random_read);

    // Note this is a very inefficient way to input data into a MappableFlatMultiSet!
    // A much better way is to insert pre-sorted data.
    std::vector<Read> buffer {};
    buffer.reserve(num_reads / 2);
    std::generate_n(std::back_inserter(buffer), num_reads / 2, generate_random_read);
    std::sort(std::begin(buffer), std::end(buffer));
    reads.insert(std::make_move_iterator(std::begin(buffer)), std::make_move_iterator(std::end(buffer)));

    // We can now query the MappableFlatMultiSet using any mappable algorithm.
    const ContigRegion test_region {contig_size / 2 - contig_size / 4, contig_size / 2 + contig_size / 4};
    std::cout << "There are " << count_overlapped(reads, test_region) << " reads overlapping with " << test_region << std::endl;
    std::cout << "There are " << count_contained(reads, test_region) << " reads contained within " << test_region << std::endl;

    // Let's do something a bit more interesting; calculate the average read quality
    // of reads contained in a region.
    const auto contained = contained_range(reads, test_region);
    const auto quality_sum = std::accumulate(std::cbegin(contained), std::cend(contained), 0.0,
                                             [] (auto curr, const auto& read) { return curr + read.quality; });
    const auto mean_quality = quality_sum / size(contained);
    std::cout << "The mean quality of reads contained in " << test_region << " is " << mean_quality << std::endl;

    // Which positions on are contig have read coverage?
    const auto covered_regions = extract_covered_regions(reads);
    const auto covered_length = sum_region_sizes(covered_regions);
    const auto covered_fraction = 100 * static_cast<double>(covered_length) / contig_size;
    std::cout << "The generated reads covered " << covered_fraction << "% of the contig: "
              << covered_regions << std::endl;

    // We can also easily get any 'intervening' regions between the covered regions.
    const auto intervening_regions = extract_intervening_regions(covered_regions, ContigRegion {0, contig_size});
    const auto intervening_length = sum_region_sizes(intervening_regions);
    std::cout << "covered_length + intervening_length = " << covered_length + intervening_length << std::endl;

    // We can also efficiently look at the coverage in a region
    const auto depths = calculate_positional_coverage(reads, reads[num_reads / 2]);
    std::cout << "The depth of each position in the region " << mapped_region(reads[num_reads / 2])
              << " is " << depths << std::endl;

    // It's easy to remove items from a MappableFlatMultiSet...
    reads.erase_overlapped(test_region);
    std::cout << "After removing reads overlapped with " << test_region
              << " there are " << reads.size() << " reads remaining" << std::endl;
}

void mappable_set_example()
{
    std::cout << "Running mappable_multiset_example..." << std::endl;

    // MappableFlatSet is similar to MappableFlatMultiSet, but duplicates are not allowed.
    // There is also no reserve method for MappableFlatSet.

    AlleleSet alleles {};
    alleles.emplace(GenomicRegion {"X", 100, 101}, "A");
    alleles.emplace(GenomicRegion {"X", 101, 102}, "C");
    alleles.emplace(GenomicRegion {"X", 101, 102}, "AC");
    assert(alleles.size() == 3);
    alleles.emplace(GenomicRegion {"X", 100, 101}, "A");
    assert(alleles.size() == 3);
}

void complex_usage_example()
{
    std::cout << "Running complex_usage_example..." << std::endl;

    // One of the most powerful of the Mappable library is the ability to mix
    // different Mappable types (assuming same underlying region type - see intro).
    // For example, we can suppose we have some genotypes

    const std::vector<Genotype> genotypes {
        Genotype {GenomicRegion {"X", 0, 2}, "CC", "CC"},
        Genotype {GenomicRegion {"X", 2, 3}, "A", "C"},
        Genotype {GenomicRegion {"X", 3, 4}, "G", "T"},
        Genotype {GenomicRegion {"X", 4, 9}, "ACGT", ""},
        Genotype {GenomicRegion {"X", 9, 10}, "A", "A"}
    };

    assert(std::is_sorted(std::cbegin(genotypes), std::cend(genotypes)));

    // What alleles are present?
    AlleleSet alleles {};
    for (const auto& genotype : genotypes) {
        alleles.insert(genotype.first);
        alleles.insert(genotype.second);
    }

    // Which alleles are overlapped with each genotype?
    for (const auto& genotype : genotypes) {
        auto overlapped = overlap_range(alleles, genotype);
        std::cout << genotype << ": " << overlapped << std::endl;
    }
    // Note we didn't need to pass a region to overlap_range, we just passed
    // the genotype directly. Because both Allele and Genotype are mappable,
    // we can easily compare them in region space.
}

void mappable_reference_wrapper_example()
{
    std::cout << "Running mappable_reference_wrapper_example..." << std::endl;

    // Sometimes you will want to store a collection of references to Mappable objects.
    // As standard C++ solutions to this (e.g. pointers or std::reference_wrapper) are not
    // themselves Mappable, you wouldn't be able to use any mappable algorithms on this collection.
    // MappableReferenceWrapper provides a solution to this.

    std::vector<Allele> alleles {};
    alleles.emplace_back(GenomicRegion {"X", 100, 101}, "A");
    alleles.emplace_back(GenomicRegion {"X", 101, 104}, "GTC");
    alleles.emplace_back(GenomicRegion {"X", 102, 103}, "T");

    std::cout << "alleles: " << alleles << std::endl;

    std::vector<AlleleReference> allele_refs {};
    allele_refs.push_back(alleles[0]);
    allele_refs.push_back(alleles[2]);

    std::cout << "allele_refs: " << alleles << std::endl;

    assert(std::is_sorted(std::cbegin(allele_refs), std::cend(allele_refs)));

    std::cout << "There is " << count_overlapped(allele_refs, alleles[1])
              << " allele ref overlapped with " << alleles[1] << ": ";
    const auto overlapped = overlap_range(allele_refs, alleles[1]);
    std::cout << overlapped << std::endl;
}

int main()
{
    std_container_example();
    mappable_multiset_example();
    mappable_set_example();
    complex_usage_example();
    mappable_reference_wrapper_example();
}
<|endoftext|>