示例#1
0
void handleRead(char *allTokens[], char response[MAX_RESPONSE_SIZE], int clientSock){
	//executes and sends read requests to the client
	if(strncmp(allTokens[0], "LOGIN", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 3);
		int val = verifyLogin(allTokens[1], allTokens[2]);
		if(snprintf(response, MAX_RESPONSE_SIZE, "%i\n", val) < 0)
		{
			perror("Snprintf failed.");
			exit(SNPRINTF_FAILED);
		}
		if(send(clientSock, response, MAX_RESPONSE_SIZE, 0) == -1)
		{
			perror("Send Failed.");
			exit(SEND_FAILED);
		}
	}
	else if(strncmp(allTokens[0], "LIST_FOLLOWEES", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 2);
		listFollowees(allTokens[1], clientSock);
	}
	else if(strncmp(allTokens[0], "LIST_OTHERS", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 2);
		int size = 1;
		char **followees = (char **)malloc(size*sizeof(char*));
		if(followees == NULL)
		{
			perror("Malloc failed");
			exit(MALLOC_FAILED);
		}
		loadFollowees(allTokens[1], &followees, &size);
		listOthers(allTokens[1], followees, clientSock, size-1);
		for(int i = 0; i < (size-1); i++)
		{
			free(followees[i]);
		}
		free(followees);
			
	}
	else if(strncmp(allTokens[0], "LIST_TWEETS", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 2);
		int size = 1;
		char **followees = (char **)malloc(size*sizeof(char*));
		if(followees == NULL)
		{
			perror("Malloc failed");
			exit(MALLOC_FAILED);
		}
		loadFollowees(allTokens[1], &followees, &size);
		listTweets(allTokens[1], followees, clientSock, size-1);
		for(int i = 0; i < (size-1); i++)
		{
			free(followees[i]);
		}
		free(followees);
	}

	else{
			exit(INVALID_SELECTION);
		}	
}
示例#2
0
void handleUpdate(char *allTokens[], char response[MAX_RESPONSE_SIZE]){
	//Executes an update and stores a response
	if(strncmp(allTokens[0], "REGISTER", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 3);
		int val = verifyRegistration(allTokens[1], allTokens[2]);
		if(snprintf(response, MAX_RESPONSE_SIZE, "%i\n", val) < 0)
		{
			perror("Snprintf failed.");
			exit(SNPRINTF_FAILED);
		}
	}
	else if(strncmp(allTokens[0], "ADD_TWEET", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 4);
		//puts(allTokens[2]);
		int val = addTweet(allTokens[1], allTokens[2], allTokens[3]);
		if(snprintf(response, MAX_RESPONSE_SIZE, "%i\n", val) < 0)
		{
			perror("Snprintf failed.");
			exit(SNPRINTF_FAILED);
		}
	}
	else if(strncmp(allTokens[0], "ADD_FOLLOWEE", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 3);
		int val = addFollowee(allTokens[1], allTokens[2]);
		if(snprintf(response, MAX_RESPONSE_SIZE, "%i\n", val) < 0)
		{
			perror("Snprintf failed.");
			exit(SNPRINTF_FAILED);
		}
	}
	else if(strncmp(allTokens[0], "REMOVE_FOLLOWEE", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 3);
		int val = removeFollowee(allTokens[1], allTokens[2]);
		if(snprintf(response, MAX_RESPONSE_SIZE, "%i\n", val) < 0)
		{
			perror("Snprintf failed.");
			exit(SNPRINTF_FAILED);
		}
	}
	else if(strncmp(allTokens[0], "DELETE_ACCOUNT", strlen(allTokens[0])) == 0){
		validateArguments(allTokens, 2);
		int val = removeEntry(allTokens[1], CREDENTIALS_FILE, CREDENTIALS_ENTRY_SIZE, NUM_FIELDS_CREDENTIALS, "%s\t%s\n", 0, &credentialsMutex); //val represents if uname was deleted from credentials file
		removeEntry(allTokens[1], TWEETS_FILE, TWEET_ENTRY_SIZE, NUM_FIELDS_TWEETS, "%s\t%s\t%s\n", 0, &tweetsMutex);
		removeEntry(allTokens[1], FOLLOWEES_FILE, FOLLOWEES_ENTRY_SIZE, NUM_FIELDS_FOLLOWEES, "%s\t%s\n", 0, &followeesMutex);
		removeEntry(allTokens[1], FOLLOWEES_FILE, FOLLOWEES_ENTRY_SIZE, NUM_FIELDS_FOLLOWEES, "%s\t%s\n", 1, &followeesMutex);
		if(snprintf(response, MAX_RESPONSE_SIZE, "%i\n", val) < 0)
		{
			perror("Snprintf failed.");
			exit(SNPRINTF_FAILED);
		}
	}
	else{
			exit(INVALID_SELECTION);
		}
		
}
示例#3
0
App::App( int argc, char ** argv ) :
	_argc( argc ),
	_argv( argv ),
	_version( NULL )
{
	validateArguments();
}
int main(int argc, char** argv)
{
    try
    {
        validateArguments(argc, argv);
        const std::string xmlPathname(argv[1]);

        six::XMLControlFactory::getInstance().addCreator(
            six::DataType::COMPLEX,
            new six::XMLControlCreatorT<six::sicd::ComplexXMLControl>());

        std::auto_ptr<io::TempFile> nitf = createNITFFromXML(xmlPathname);
        six::NITFReadControl reader;
        reader.load(nitf->pathname());

        // Make sure ComplexData got read in
        logging::Logger log;
        std::auto_ptr<six::sicd::ComplexData> originalData =
                six::sicd::Utilities::parseDataFromFile(xmlPathname,
                std::vector<std::string>(),
                log);

        mem::SharedPtr<const six::Container> container = reader.getContainer();
        // container retains ownership of this pointer
        const six::Data* readData = container->getData(0);

        if (*readData == *originalData)
        {
            std::cout << "Test passed\n";
            return 0;
        }
        else
        {
            std::cerr << "Round-tripped data not the same as original."
                    << "Test failed.\n";
            return 1;
        }
    }
    catch (const except::Exception& e)
    {
        std::cerr << e.getMessage() << std::endl;
        return 1;
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
        return 1;
    }
    catch (...)
    {
        std::cerr << "Unknown exception" << std::endl;
        return 1;
    }
}
示例#5
0
	// Handle opcodes
	// scriptPtr - pointer to script program (from the engine)
	// func - opcode handler
	// hasReturn - true if opcode has return value (is expression)
	void __thiscall handleOpcode(TProgram* program, void(*func)(), int argNum, bool hasReturn) {
		assert(argNum < OP_MAX_ARGUMENTS);

		// reset state after previous
		resetState(program, argNum);

		// process arguments on stack (reverse order)
		for (int i = argNum - 1; i >= 0; i--) {
			// get argument from stack
			DWORD rawValueType = InterpretPopShort(program);
			DWORD rawValue = InterpretPopLong(program);
			SfallDataType type = static_cast<SfallDataType>(getSfallTypeByScriptType(rawValueType));

			// retrieve string argument
			if (type == DATATYPE_STR) {
				_args.at(i) = InterpretGetString(program, rawValue, rawValueType);
			} else {
				_args.at(i) = ScriptValue(type, rawValue);
			}
		}
		// flag that arguments passed are valid
		bool argumentsValid = true;

		// check if metadata is available
		OpcodeMetaTableType::iterator it = opcodeMetaTable.find(func);
		if (it != opcodeMetaTable.end()) {
			const SfallOpcodeMetadata* meta = it->second;

			// automatically validate argument types
			argumentsValid = validateArguments(meta->argTypeMasks, argNum, meta->name);
		}

		// call opcode handler if arguments are valid (or no automatic validation was done)
		if (argumentsValid) {
			func();
		}

		// process return value
		if (hasReturn) {
			if (_ret.type() == DATATYPE_NONE) {
				// if no value was set in handler, force return 0 to avoid stack error
				_ret = ScriptValue(0);
			}
			DWORD rawResult = _ret.rawValue();
			if (_ret.type() == DATATYPE_STR) {
				rawResult = InterpretAddString(program, _ret.asString());
			}
			InterpretPushLong(program, rawResult);
			InterpretPushShort(program, getScriptTypeBySfallType(_ret.type()));
		}
	}
示例#6
0
int main(int argc, char * argv[]) {
	SETTINGS settings;
	
	parseArguments(argc, argv, &settings);
	         
	if( settings.help == SET ) {
		printHelpAndExit(stdout, EXIT_SUCCESS);
	}
	
	validateArguments(&settings);
	
	printSymbolicLinkInfo(&settings); //hlavna funkcionalita programu

	return EXIT_SUCCESS;
}
示例#7
0
int main( int argc, char ** argv )
{
	try
	{
		XMLPlatformUtils::Initialize();
	}
	catch( const XMLException& e )
	{
		cerr<< "Error during Xerces-c Initialization\n"
			<< "  Exception message:"
			<< DOMString(e.getMessage()) << endl;
		return 1;
	}

	if ( false == validateArguments(argc, argv))
	{
		usage("EXE-NAME: ");
		//exit (99);
	}

	EppParser *parser = new EppParser();

	EppXmlValidator* validator = getValidator();
	
	if (1 == argc)
	{
		validator->loadXSD(getenv("PWD"));
	}
	else if ((2 == argc) && (0 == strcmp(argv[1], ".")))
	{
		validator->loadXSD(getenv("PWD"));
	}
	else
	{
		validator->loadXSD(argv[1]);
	}


	runEppTestFee(*parser);

	delete parser;

	delete validator;
	XMLPlatformUtils::Terminate();
}
示例#8
0
int main(int argc, char **argv) {
    int rank;
    int size;
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        clock_gettime(CLOCK_MONOTONIC, &start);
        validateArguments(argc, argv);
    }

    doJob(rank, size);
    if (rank == 0) {
        clock_gettime(CLOCK_MONOTONIC, &end);
        CulculateAndPrintTime();
    }
    MPI_Finalize();


}
//--------------------------------------------------------------------------------------------------
/// 
//--------------------------------------------------------------------------------------------------
void RicfCreateMultipleFractures::execute()
{
    using TOOLS = RicfApplicationTools;

    RimProject* project = RiaApplication::instance()->project();
    RiuCreateMultipleFractionsUi* settings = project->dialogData()->multipleFractionsData();

    // Get case and fracture template
    auto gridCase = TOOLS::caseFromId(m_caseId);
    auto fractureTemplate = fractureTemplateFromId(m_templateId);
    std::vector<RimWellPath*> wellPaths;

    // Find well paths
    {
        QStringList wellsNotFound;
        wellPaths = TOOLS::wellPathsFromNames(TOOLS::toQStringList(m_wellPathNames), &wellsNotFound);
        if (!wellsNotFound.empty())
        {
            RiaLogging::error(QString("createMultipleFractures: These well paths were not found: ") + wellsNotFound.join(", "));
        }
    }

    if (!gridCase)
    {
        RiaLogging::error(QString("createMultipleFractures: Could not find case with ID %1").arg(m_caseId));
    }

    if (!fractureTemplate)
    {
        RiaLogging::error(QString("createMultipleFractures: Could not find fracture template with ID %1").arg(m_templateId));
    }

    if (gridCase && fractureTemplate && !wellPaths.empty() && validateArguments())
    {
        RicCreateMultipleFracturesOptionItemUi* options = new RicCreateMultipleFracturesOptionItemUi();
        caf::CmdFeatureManager*                 commandManager = caf::CmdFeatureManager::instance();
        auto feature = dynamic_cast<RicCreateMultipleFracturesFeature*>(commandManager->getCommandFeature("RicCreateMultipleFracturesFeature"));

        // Default layers
        int topLayer = m_topLayer;
        int baseLayer = m_baseLayer;
        if (feature && (topLayer < 0 || baseLayer < 0))
        {
            auto ijkRange = feature->ijkRangeForGrid(gridCase);
            if (topLayer < 0) topLayer = static_cast<int>(ijkRange.first.z());
            if (baseLayer < 0) baseLayer = static_cast<int>(ijkRange.second.z());
        }
        options->setValues(topLayer, baseLayer, fractureTemplate, m_spacing);

        settings->clearWellPaths();
        for (auto wellPath : wellPaths)
        {
            settings->addWellPath(wellPath);
        }

        settings->setValues(gridCase, m_minDistFromWellTd, m_maxFracturesPerWell);
        settings->clearOptions();
        settings->insertOptionItem(nullptr, options);


        if (feature)
        {
            if (m_action == MultipleFractures::APPEND_FRACTURES)    feature->appendFractures();
            if (m_action == MultipleFractures::REPLACE_FRACTURES)   feature->replaceFractures();
        }
    }
}
示例#10
0
int main(int argc, char *argv[]) {
// This is a program to find the best matches for a given User in a database of
// Users with registered preferences using the pearson-correlation algorithm.
// The MPI strategy will be, send ALL the processes the table with all Users'
// ratings (which is invariant). Since the data each process needs to compute
// is also contained within the invariant data, no further data sending is nee-
// ded. Then, each process will find the correlation values for one User at a
// time against all other Users in the database, then returning a list with
// just the top B correlated Users, saving space by not having to store a huge
// table with the correlation values between all possible pairs of Users.
    double t1 = MPI_Wtime(); // START COUNTING THE TIME
    MPI_Status status;
    // This will allow to identify exactly which Worker sent a response to the
    // Master, while receiving requests arbitrarily (no Worker specified in
    // 'source ID' field). This is so we don't block waiting for a specific
    // Worker to answer, because the Workers may finish their operations fast-
    // er than others, so instead, we listen to whatever Worker answers, and
    // then we see what ID this Worker has so we can place its response in
    // the place where it belongs, to start merging all the responses.
    int RC, NUM_PROCS, TASK_ID, NUM_WORKERS;
    // RC: The resulting message from several MPI commands to check for errors.
    // NUM_PROCS: The total number of processes counting Workers and Master.
    // TASK_ID: The ID of this particular process. Master is always 0.
    // NUM_WORKERS: The amount of Workers not counting the Master.
    if((RC = MPI_Init(&argc, &argv)) != MPI_SUCCESS) {
        fprintf(stderr, "Cannot initialize MPI_Init. Exiting.\n");
        MPI_Abort(MPI_COMM_WORLD, RC);
        exit(1);
    }
    // Init MPI, pass the argc and argv of the original program to all Workers
    // so that they will be initialized the same way as the Master Node.
    RC = MPI_Comm_rank(MPI_COMM_WORLD, &TASK_ID);
    // Get TASK_ID of this process, each process will have a different ID.
    RC = MPI_Comm_size(MPI_COMM_WORLD, &NUM_PROCS);
    // Get the total number of processes, given via shell with -np flag.
    int LEN;
    char NAME[MPI_MAX_PROCESSOR_NAME];
    // To store the current host name.
    MPI_Get_processor_name(NAME, &LEN);
    NUM_WORKERS = NUM_PROCS - 1;
    // The number of Workers is the amount of total processes, minus 1.
    printf("Hello! I'm process %d out of %d processes, on host %s.\n",
           TASK_ID, NUM_PROCS, NAME);
    // DEBUG printing to identify that all processes are up and running.
    int NUM_USERS, NUM_MOVIES, NUM_BEST;
    // NUM_USERS:  Amount of registered Users
    // NUM_MOVIES: Amount of available Movies
    // NUM_BEST: The top M values to select from a Users' correlation list,
    // this means, the top M Users a given User is the most correlated with.
    int *matrixUI;
    // Lets initialize the matrix for User->Movie rating values.
    // matrixUI[UserAmount][MovieAmount]
    // User = Y/i/rows, Movie = X/j/cols
    // matrixUI[i][j] == User i rating over Movie j
    int *params = new int[3];
    // To pass the parameters between Nodes.
    if(TASK_ID == MASTER) {
    // Set-up Code for Master Node
        vector<string> matrixName;
        matrixName = getMatrixName();
        if(matrixName.size() < 1) {
        // Exit the program if no text file was found in the ratings folder.
            fprintf(stderr, "Input file was not found.\n");
            MPI_Abort(MPI_COMM_WORLD, RC);
            exit(1);
        }
        string fname = matrixName[0];
        ifstream iss(fname);
        iss >> NUM_USERS >> NUM_MOVIES >> NUM_BEST;
        params[0] = NUM_USERS;
        params[1] = NUM_MOVIES;
        params[2] = NUM_BEST;
        for(int TARGET_ID = 1; TARGET_ID <= NUM_WORKERS; TARGET_ID++) {
        // Send to each Worker the parameters of the program.
           MPI_Send(&(params[0]), 3, MPI_INT, TARGET_ID,
                    FROM_MASTER_P, MPI_COMM_WORLD);
        }
        validateArguments(NUM_USERS, NUM_MOVIES, NUM_BEST);
        // If the three given parameters are valid, proceed to read the
        // matrix containing the ratings each User has for each Movie.
        matrixUI = new int[NUM_USERS * NUM_MOVIES];
        for(int i = 0; i < NUM_USERS; i++) {
            for(int j = 0; j < NUM_MOVIES; j++) {
                int rating;
                iss >> rating;
                matrixUI[(i * NUM_MOVIES) + j] = rating;
            }
        }
        for(int TARGET_ID = 1; TARGET_ID <= NUM_WORKERS; TARGET_ID++) {
        // Now that the matrix has been read, lets send it to all Workers.
            MPI_Send(&(matrixUI[0]), NUM_USERS * NUM_MOVIES, MPI_INT, TARGET_ID,
                     FROM_MASTER, MPI_COMM_WORLD);
        }
    }
示例#11
0
int main(int argc, char** argv)
{
	const char *progname;
	char 	*switchAddr;
	
	int 	status;
	int 	verbose;
	int 	init;
	int 	ch;

	int 	channel;
	int 	relayState;

	int 	devAddr;
	int 	bInitialized;

	// set defaults
	init 		= 0;
	verbose 	= ONION_VERBOSITY_NORMAL;

	switchAddr 	= malloc(RELAY_EXP_ADDR_SWITCH_NUM * sizeof *switchAddr);
	strcpy(switchAddr, RELAY_EXP_ADDR_SWITCH_DEFAULT_VAL);

	// save the program name
	progname 	= argv[0];	

	//// parse the option arguments
	while ((ch = getopt(argc, argv, "vqhis:")) != -1) {
		switch (ch) {
		case 'v':
			// verbose output
			verbose++;
			break;
		case 'q':
			// quiet output
			verbose = ONION_VERBOSITY_NONE;
			break;
		case 'i':
			// perform init sequence
			init 	= 1;
			break;
		case 's':
			// capture binary 
			strcpy (switchAddr, optarg);
			break;
		default:
			usage(progname);
			return 0;
		}
	}

	// set the verbosity
	onionSetVerbosity(verbose);


	// advance past the option arguments
	argc 	-= optind;
	argv	+= optind;


	// process the switch address
	status = processSwitchAddr(switchAddr, &devAddr);
	if (status == EXIT_FAILURE) {
		usage(progname);
		onionPrint(ONION_SEVERITY_FATAL, "ERROR: invalid switch address argument!\n");
		return 0;
	}
	if (strcmp(switchAddr, RELAY_EXP_ADDR_SWITCH_DEFAULT_VAL) != 0) {
		onionPrint(ONION_SEVERITY_INFO, "> Switch configuration: %s\n", switchAddr);
	}


	// check if just initialization
	if ( argc == 0 && init == 1 ) {
		status = relayDriverInit(devAddr);
		if (status == EXIT_FAILURE) {
			onionPrint(ONION_SEVERITY_FATAL, "main-relay-exp:: relay init failed!\n");
		}
		return 0;
	}

	// ensure correct number of arguments
	if ( argc != 2) {
		usage(progname);
		onionPrint(ONION_SEVERITY_FATAL, "ERROR: invalid amount of arguments!\n");
		return 0;
	}


	//// parse the arguments
	// first arg - channel
	channel 	= readChannelArgument(argv[0]);

	// second arg - relay state (on or off)
	if 	(	strcmp(argv[1], "off") == 0 ||
			strcmp(argv[1], "Off") == 0 ||
			strcmp(argv[1], "OFF") == 0
		) 
	{
		relayState 	= 0;
	}
	else if (	strcmp(argv[1], "on") == 0 ||
				strcmp(argv[1], "On") == 0 ||
				strcmp(argv[1], "ON") == 0
		) 
	{
		relayState 	= 1;
	}
	else {
		relayState 	= (int)strtol(argv[1], NULL, 10);
	}

	// validate the arguments
	status 	= validateArguments(channel, relayState);
	if (status == EXIT_FAILURE) {
		return 0;
	}


	//// RELAY PROGRAMMING
	// check if initialized
	status = relayCheckInit(devAddr, &bInitialized);

	// exit the app if i2c reads fail
	if (status == EXIT_FAILURE) {
		onionPrint(ONION_SEVERITY_FATAL, "> ERROR: Relay Expansion not found!\n");
		return 0;
	}
	

	// perform initialization
	if (init == 1 || bInitialized == 0) {
		status 	= relayDriverInit(devAddr);
		if (status == EXIT_FAILURE) {
			onionPrint(ONION_SEVERITY_FATAL, "main-relay-exp:: relay init failed!\n");
		}
	}

	// set the relay state
	if (channel < 0) {
		// program both relays at once
		status 	= relaySetAllChannels(devAddr, relayState);
		if (status == EXIT_FAILURE) {
			onionPrint(ONION_SEVERITY_FATAL, "main-relay-exp:: all relay setup failed!\n");
		}
	}
	else {
		// program just one relay
		status 	= relaySetChannel(devAddr, channel, relayState);
		if (status == EXIT_FAILURE) {
			onionPrint(ONION_SEVERITY_FATAL, "main-relay-exp:: relay %d setup failed!\n", channel);
		}
	}


	return 0;
}
示例#12
0
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int
main( int argc, char** argv) {
    int num_clusters;
    
    // For profiling 
    clock_t seed_start, seed_end, seed_total = 0;
    clock_t regroup_start, regroup_end, regroup_total = 0;
    int regroup_iterations = 0;
    clock_t params_start, params_end, params_total = 0;
    int params_iterations = 0;
    clock_t constants_start, constants_end, constants_total = 0;
    int constants_iterations = 0;
    clock_t total_timer = clock();
    double total_time = 0;
    clock_t io_timer;
    double io_time = 0;
    clock_t cpu_timer;
    double cpu_time = 0;

    io_timer = clock();
    // Validate the command-line arguments, parse # of clusters, etc 
    if(validateArguments(argc,argv,&num_clusters)) {
        return 1; //Bard args
    }
    
    int num_dimensions;
    int num_events;
    
    // Read FCS data   
    PRINT("Parsing input file...");
    // This stores the data in a 1-D array with consecutive values being the dimensions from a single event
    // (num_events by num_dimensions matrix)
    float* fcs_data_by_event = readData(argv[2],&num_dimensions,&num_events);    

    if(!fcs_data_by_event) {
        printf("Error parsing input file. This could be due to an empty file ");
        printf("or an inconsistent number of dimensions. Aborting.\n");
        return 1;
    }
    
    // Transpose the event data (allows coalesced access pattern in E-step kernel)
    // This has consecutive values being from the same dimension of the data 
    // (num_dimensions by num_events matrix)
    float* fcs_data_by_dimension  = (float*) malloc(sizeof(float)*num_events*num_dimensions);
    
    for(int e=0; e<num_events; e++) {
        for(int d=0; d<num_dimensions; d++) {
            fcs_data_by_dimension[d*num_events+e] = fcs_data_by_event[e*num_dimensions+d];
        }
    }    

    io_time += (double)(clock() - io_timer);
   
    PRINT("Number of events: %d\n",num_events);
    PRINT("Number of dimensions: %d\n",num_dimensions);
    PRINT("Number of target clusters: %d\n\n",num_clusters);
   
    cpu_timer = clock();
    
    // Setup the cluster data structures on host
    clusters_t clusters;
    clusters.N = (float*) malloc(sizeof(float)*num_clusters);
    clusters.pi = (float*) malloc(sizeof(float)*num_clusters);
    clusters.constant = (float*) malloc(sizeof(float)*num_clusters);
    clusters.avgvar = (float*) malloc(sizeof(float)*num_clusters);
    clusters.means = (float*) malloc(sizeof(float)*num_dimensions*num_clusters);
    clusters.R = (float*) malloc(sizeof(float)*num_dimensions*num_dimensions*num_clusters);
    clusters.Rinv = (float*) malloc(sizeof(float)*num_dimensions*num_dimensions*num_clusters);
    clusters.memberships = (float*) malloc(sizeof(float)*num_events*num_clusters);
    if(!clusters.means || !clusters.R || !clusters.Rinv || !clusters.memberships) { 
        printf("ERROR: Could not allocate memory for clusters.\n"); 
        return 1; 
    }
    DEBUG("Finished allocating memory on host for clusters.\n");
    
    float rissanen;
    
    //////////////// Initialization done, starting kernels //////////////// 
    DEBUG("Invoking seed_clusters kernel.\n");
    fflush(stdout);

    // seed_clusters sets initial pi values, 
    // finds the means / covariances and copies it to all the clusters
    // TODO: Does it make any sense to use multiple blocks for this?
    seed_start = clock();
    seed_clusters(fcs_data_by_event, &clusters, num_dimensions, num_clusters, num_events);
   
    DEBUG("Invoking constants kernel.\n");
    // Computes the R matrix inverses, and the gaussian constant
    //constants_kernel<<<num_clusters, num_threads>>>(d_clusters,num_clusters,num_dimensions);
    constants(&clusters,num_clusters,num_dimensions);
    constants_iterations++;
    seed_end = clock();
    seed_total = seed_end - seed_start;
    
    // Calculate an epsilon value
    //int ndata_points = num_events*num_dimensions;
    float epsilon = (1+num_dimensions+0.5*(num_dimensions+1)*num_dimensions)*log((float)num_events*num_dimensions)*0.01;
    float likelihood, old_likelihood;
    int iters;
    
    epsilon = 1e-6;
    PRINT("Gaussian.cu: epsilon = %f\n",epsilon);

    /*************** EM ALGORITHM *****************************/
    
    // do initial regrouping
    // Regrouping means calculate a cluster membership probability
    // for each event and each cluster. Each event is independent,
    // so the events are distributed to different blocks 
    // (and hence different multiprocessors)
    DEBUG("Invoking regroup (E-step) kernel with %d blocks.\n",NUM_BLOCKS);
    regroup_start = clock();
    estep1(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events,&likelihood);
    estep2(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events,&likelihood);
    //estep2b(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events,&likelihood);
    regroup_end = clock();
    regroup_total += regroup_end - regroup_start;
    regroup_iterations++;
    DEBUG("Regroup Kernel Iteration Time: %f\n\n",((double)(regroup_end-regroup_start))/CLOCKS_PER_SEC);

    DEBUG("Likelihood: %e\n",likelihood);

    float change = epsilon*2;
    
    PRINT("Performing EM algorithm on %d clusters.\n",num_clusters);
    iters = 0;
    // This is the iterative loop for the EM algorithm.
    // It re-estimates parameters, re-computes constants, and then regroups the events
    // These steps keep repeating until the change in likelihood is less than some epsilon        
    while(iters < MIN_ITERS || (fabs(change) > epsilon && iters < MAX_ITERS)) {
        old_likelihood = likelihood;
        
        DEBUG("Invoking reestimate_parameters (M-step) kernel.\n");
        params_start = clock();
        // This kernel computes a new N, pi isn't updated until compute_constants though
        mstep_n(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events);
        mstep_mean(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events);
        mstep_covar(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events);
        params_end = clock();
        params_total += params_end - params_start;
        params_iterations++;
        DEBUG("Model M-Step Iteration Time: %f\n\n",((double)(params_end-params_start))/CLOCKS_PER_SEC);
        //return 0; // RETURN FOR FASTER PROFILING
        
        DEBUG("Invoking constants kernel.\n");
        // Inverts the R matrices, computes the constant, normalizes cluster probabilities
        constants_start = clock();
        constants(&clusters,num_clusters,num_dimensions);
        constants_end = clock();
        constants_total += constants_end - constants_start;
        constants_iterations++;
        DEBUG("Constants Kernel Iteration Time: %f\n\n",((double)(constants_end-constants_start))/CLOCKS_PER_SEC);

        DEBUG("Invoking regroup (E-step) kernel with %d blocks.\n",NUM_BLOCKS);
        regroup_start = clock();
        // Compute new cluster membership probabilities for all the events
        estep1(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events,&likelihood);
        estep2(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events,&likelihood);
        //estep2b(fcs_data_by_dimension,&clusters,num_dimensions,num_clusters,num_events,&likelihood);
        regroup_end = clock();
        regroup_total += regroup_end - regroup_start;
        regroup_iterations++;
        DEBUG("E-step Iteration Time: %f\n\n",((double)(regroup_end-regroup_start))/CLOCKS_PER_SEC);
    
        change = likelihood - old_likelihood;
        DEBUG("likelihood = %f\n",likelihood);
        DEBUG("Change in likelihood: %f\n",change);

        iters++;

    }
    
    // Calculate Rissanen Score
    rissanen = -likelihood + 0.5*(num_clusters*(1+num_dimensions+0.5*(num_dimensions+1)*num_dimensions)-1)*logf((float)num_events*num_dimensions);
    PRINT("\nFinal rissanen Score was: %f, with %d clusters.\n",rissanen,num_clusters);
    
    char* result_suffix = ".results";
    char* summary_suffix = ".summary";
    int filenamesize1 = strlen(argv[3]) + strlen(result_suffix) + 1;
    int filenamesize2 = strlen(argv[3]) + strlen(summary_suffix) + 1;
    char* result_filename = (char*) malloc(filenamesize1);
    char* summary_filename = (char*) malloc(filenamesize2);
    strcpy(result_filename,argv[3]);
    strcpy(summary_filename,argv[3]);
    strcat(result_filename,result_suffix);
    strcat(summary_filename,summary_suffix);
    
    PRINT("Summary filename: %s\n",summary_filename);
    PRINT("Results filename: %s\n",result_filename);
    cpu_time += (double)(clock() - cpu_timer);
    
    io_timer = clock();
    // Open up the output file for cluster summary
    FILE* outf = fopen(summary_filename,"w");
    if(!outf) {
        printf("ERROR: Unable to open file '%s' for writing.\n",argv[3]);
    }

    // Print the clusters with the lowest rissanen score to the console and output file
    for(int c=0; c<num_clusters; c++) {
        //if(saved_clusters.N[c] == 0.0) {
        //    continue;
        //}
        if(ENABLE_PRINT) {
            // Output the final cluster stats to the console
            PRINT("Cluster #%d\n",c);
            printCluster(clusters,c,num_dimensions);
            PRINT("\n\n");
        }

        if(ENABLE_OUTPUT) {
            // Output the final cluster stats to the output file        
            fprintf(outf,"Cluster #%d\n",c);
            writeCluster(outf,clusters,c,num_dimensions);
            fprintf(outf,"\n\n");
        }
    }
    
    // Print profiling information
    printf("Program Component\tTotal\tIters\tTime Per Iteration\n");
    printf("        Seed Kernel:\t%7.4f\t%d\t%7.4f\n",seed_total/(double)CLOCKS_PER_SEC,1, (double) seed_total / (double) CLOCKS_PER_SEC);
    printf("      E-step Kernel:\t%7.4f\t%d\t%7.4f\n",regroup_total/(double)CLOCKS_PER_SEC,regroup_iterations, (double) regroup_total / (double) CLOCKS_PER_SEC / (double) regroup_iterations);
    printf("      M-step Kernel:\t%7.4f\t%d\t%7.4f\n",params_total/(double)CLOCKS_PER_SEC,params_iterations, (double) params_total / (double) CLOCKS_PER_SEC / (double) params_iterations);
    printf("   Constants Kernel:\t%7.4f\t%d\t%7.4f\n",constants_total/(double)CLOCKS_PER_SEC,constants_iterations, (double) constants_total / (double) CLOCKS_PER_SEC / (double) constants_iterations);    
   
    // Write profiling info to summary file
    fprintf(outf,"Program Component\tTotal\tIters\tTime Per Iteration\n");
    fprintf(outf,"        Seed Kernel:\t%7.4f\t%d\t%7.4f\n",seed_total/(double)CLOCKS_PER_SEC,1, (double) seed_total / (double) CLOCKS_PER_SEC);
    fprintf(outf,"      E-step Kernel:\t%7.4f\t%d\t%7.4f\n",regroup_total/(double)CLOCKS_PER_SEC,regroup_iterations, (double) regroup_total / (double) CLOCKS_PER_SEC / (double) regroup_iterations);
    fprintf(outf,"      M-step Kernel:\t%7.4f\t%d\t%7.4f\n",params_total/(double)CLOCKS_PER_SEC,params_iterations, (double) params_total / (double) CLOCKS_PER_SEC / (double) params_iterations);
    fprintf(outf,"   Constants Kernel:\t%7.4f\t%d\t%7.4f\n",constants_total/(double)CLOCKS_PER_SEC,constants_iterations, (double) constants_total / (double) CLOCKS_PER_SEC / (double) constants_iterations);    
    fclose(outf);
    
    
    // Open another output file for the event level clustering results
    FILE* fresults = fopen(result_filename,"w");
   
    if(ENABLE_OUTPUT) { 
        for(int i=0; i<num_events; i++) {
            for(int d=0; d<num_dimensions-1; d++) {
                fprintf(fresults,"%f,",fcs_data_by_event[i*num_dimensions+d]);
            }
            fprintf(fresults,"%f",fcs_data_by_event[i*num_dimensions+num_dimensions-1]);
            fprintf(fresults,"\t");
            for(int c=0; c<num_clusters-1; c++) {
                fprintf(fresults,"%f,",clusters.memberships[c*num_events+i]);
            }
            fprintf(fresults,"%f",clusters.memberships[(num_clusters-1)*num_events+i]);
            fprintf(fresults,"\n");
        }
    }
    fclose(fresults); 
    io_time += (double)(clock() - io_timer);
    printf("\n");
    printf( "I/O time: %f (ms)\n", 1000.0*io_time/CLOCKS_PER_SEC);
    printf( "CPU processing time: %f (ms)\n", 1000.0*cpu_time/CLOCKS_PER_SEC);
    total_time += (double)(clock() - total_timer);
    printf( "Total time: %f (ms)\n", 1000.0*total_time/CLOCKS_PER_SEC);
 
    // cleanup host memory
    free(fcs_data_by_event);
    free(fcs_data_by_dimension);
    free(clusters.N);
    free(clusters.pi);
    free(clusters.constant);
    free(clusters.avgvar);
    free(clusters.means);
    free(clusters.R);
    free(clusters.Rinv);
    free(clusters.memberships);

    return 0;
}