void enkf_main_initialize_from_scratch_with_bool_vector(enkf_main_type * enkf_main , const stringlist_type * param_list ,const bool_vector_type * iens_mask , init_mode_type init_mode) { int num_cpu = 4; int ens_size = enkf_main_get_ensemble_size( enkf_main ); thread_pool_type * tp = thread_pool_alloc( num_cpu , true ); arg_pack_type ** arg_list = util_calloc( ens_size , sizeof * arg_list ); int i; int iens; for (iens = 0; iens < ens_size; iens++) { arg_list[iens] = arg_pack_alloc(); if (bool_vector_safe_iget(iens_mask , iens)) { arg_pack_append_ptr( arg_list[iens] , enkf_main ); arg_pack_append_const_ptr( arg_list[iens] , param_list ); arg_pack_append_int( arg_list[iens] , iens ); arg_pack_append_int( arg_list[iens] , init_mode ); thread_pool_add_job( tp , enkf_main_initialize_from_scratch_mt , arg_list[iens]); } } thread_pool_join( tp ); for (i = 0; i < ens_size; i++) { arg_pack_free( arg_list[i] ); } free( arg_list ); thread_pool_free( tp ); }
void matrix_inplace_matmul_mt2(matrix_type * A, const matrix_type * B , thread_pool_type * thread_pool){ int num_threads = thread_pool_get_max_running( thread_pool ); arg_pack_type ** arglist = util_malloc( num_threads * sizeof * arglist ); int it; thread_pool_restart( thread_pool ); { int rows = matrix_get_rows( A ) / num_threads; int rows_mod = matrix_get_rows( A ) % num_threads; int row_offset = 0; for (it = 0; it < num_threads; it++) { int row_size; arglist[it] = arg_pack_alloc(); row_size = rows; if (it < rows_mod) row_size += 1; arg_pack_append_int(arglist[it] , row_offset ); arg_pack_append_int(arglist[it] , row_size ); arg_pack_append_ptr(arglist[it] , A ); arg_pack_append_const_ptr(arglist[it] , B ); thread_pool_add_job( thread_pool , matrix_inplace_matmul_mt__ , arglist[it]); row_offset += row_size; } } thread_pool_join( thread_pool ); for (it = 0; it < num_threads; it++) arg_pack_free( arglist[it] ); free( arglist ); }
void ensemble_init( ensemble_type * ensemble , config_type * config) { /*1 : Loading ensembles and settings from the config instance */ /*1a: Loading the eclipse summary cases. */ { thread_pool_type * tp = thread_pool_alloc( LOAD_THREADS , true ); { int i,j; for (i=0; i < config_get_occurences( config , "CASE_LIST"); i++) { const stringlist_type * case_list = config_iget_stringlist_ref( config , "CASE_LIST" , i ); for (j=0; j < stringlist_get_size( case_list ); j++) ensemble_load_from_glob( ensemble , stringlist_iget( case_list , j ) , tp); } } thread_pool_join( tp ); thread_pool_free( tp ); } { const sum_case_type * tmp = vector_iget_const( ensemble->data , 0 ); ensemble->refcase = tmp->ecl_sum; } /*1b: Other config settings */ if (config_item_set( config , "NUM_INTERP" )) ensemble->num_interp = config_iget_as_int( config , "NUM_INTERP" , 0 , 0 ); /*2: Remaining initialization */ ensemble_init_time_interp( ensemble ); if (vector_get_size( ensemble->data ) < MIN_SIZE ) util_exit("Sorry - quantiles make no sense with with < %d realizations; should have ~> 100.\n" , MIN_SIZE); }
void enkf_main_initialize_from_scratch(enkf_main_type * enkf_main , const stringlist_type * param_list , int iens1 , int iens2, init_mode_enum init_mode) { int num_cpu = 4; thread_pool_type * tp = thread_pool_alloc( num_cpu , true ); int ens_sub_size = (iens2 - iens1 + 1) / num_cpu; arg_pack_type ** arg_list = util_calloc( num_cpu , sizeof * arg_list ); int i; printf("Setting up ensemble members from %d to %d", iens1, iens2); if (init_mode == INIT_CONDITIONAL) { printf(" using conditional initialization (keep existing parameter values).\n"); } else if (init_mode == INIT_FORCE) { printf(" using forced initialization (initialize from scratch).\n"); } else if (init_mode == INIT_NONE) { printf(" not initializing at all.\n"); } fflush( stdout ); for (i = 0; i < num_cpu; i++) { arg_list[i] = arg_pack_alloc(); arg_pack_append_ptr( arg_list[i] , enkf_main ); arg_pack_append_const_ptr( arg_list[i] , param_list ); { int start_iens = i * ens_sub_size; int end_iens = start_iens + ens_sub_size; if (i == (num_cpu - 1)){ end_iens = iens2 + 1; /* Input is upper limit inclusive. */ if(ens_sub_size == 0) start_iens = iens1; /* Don't necessarily want to start from zero when ens_sub_size = 0*/ } arg_pack_append_int( arg_list[i] , start_iens ); arg_pack_append_int( arg_list[i] , end_iens ); } arg_pack_append_int( arg_list[i] , init_mode ); thread_pool_add_job( tp , enkf_main_initialize_from_scratch_mt , arg_list[i]); } thread_pool_join( tp ); for (i = 0; i < num_cpu; i++) arg_pack_free( arg_list[i] ); free( arg_list ); thread_pool_free( tp ); printf("Done setting up ensemble.\n"); }
void thread_test() { time_map_type * time_map = time_map_alloc( ); { int pool_size = 1000; thread_pool_type * tp = thread_pool_alloc( pool_size/2 , true ); thread_pool_add_job( tp , update_time_map , time_map ); thread_pool_join(tp); thread_pool_free(tp); } { int i; for (i=0; i < MAP_SIZE; i++) test_assert_true( time_map_iget( time_map , i ) == i ); } time_map_free( time_map ); }
void test_runpath_list() { runpath_list_type * list = runpath_list_alloc(); test_assert_int_equal( runpath_list_size( list ) , 0 ); runpath_list_add( list , 3 , 0, "path" , "base"); runpath_list_add( list , 2 , 0, "path" , "base"); runpath_list_add( list , 1 , 0, "path" , "base"); runpath_list_add( list , 3 , 1, "path" , "base"); runpath_list_add( list , 2 , 1, "path" , "base"); runpath_list_add( list , 1 , 1, "path" , "base"); test_assert_int_equal( runpath_list_size( list ) , 6 ); test_assert_int_equal( runpath_list_iget_iens( list , 0 ) , 3 ); test_assert_int_equal( runpath_list_iget_iens( list , 2 ) , 1 ); test_assert_int_equal( runpath_list_iget_iter( list , 3 ) , 1 ); runpath_list_sort( list ); test_assert_int_equal( runpath_list_iget_iens( list , 0 ) , 1 ); test_assert_int_equal( runpath_list_iget_iens( list , 4 ) , 3 ); runpath_list_clear( list ); test_assert_int_equal( runpath_list_size( list ) , 0 ); test_assert_string_equal( runpath_list_get_line_fmt( list ) , RUNPATH_LIST_DEFAULT_LINE_FMT ); { const char * other_line = "%d %s %s"; runpath_list_set_line_fmt( list , other_line ); test_assert_string_equal( runpath_list_get_line_fmt( list ) , other_line ); } runpath_list_set_line_fmt( list , NULL ); test_assert_string_equal( runpath_list_get_line_fmt( list ) , RUNPATH_LIST_DEFAULT_LINE_FMT ); { const int block_size = 100; const int threads = 100; thread_pool_type * tp = thread_pool_alloc( threads , true ); int it; for (it = 0; it < threads; it++) { int iens_offset = it * block_size; arg_pack_type * arg_pack = arg_pack_alloc(); arg_pack_append_ptr( arg_pack , list ); arg_pack_append_int( arg_pack , iens_offset ); arg_pack_append_int( arg_pack , block_size ); thread_pool_add_job( tp , add_pathlist , arg_pack ); } thread_pool_join( tp ); test_assert_int_equal( runpath_list_size( list ) , block_size * threads ); runpath_list_sort( list ); { int iens; for (iens = 0; iens < block_size * threads; iens++) test_assert_int_equal( runpath_list_iget_iens( list , iens ) , iens ); } { test_work_area_type * work_area = test_work_area_alloc("enkf_runpath_list" ); const char *filename = "runpath_list.txt"; { FILE * stream = util_fopen( filename, "w"); runpath_list_fprintf( list , stream ); fclose( stream ); } { int file_iens; int file_iter; char file_path[256]; char file_base[256]; int iens; FILE * stream = util_fopen( filename, "r"); for (iens = 0; iens < threads * block_size; iens++) { int fscanf_return = fscanf( stream , "%d %s %s %d" , &file_iens , file_path , file_base, &file_iter); test_assert_int_equal(fscanf_return, 4 ); test_assert_int_equal( file_iens , iens ); test_assert_int_equal( file_iter , 0 ); } fclose( stream ); } test_work_area_free( work_area ); } } runpath_list_free( list ); }
void job_queue_run_jobs(job_queue_type * queue , int num_total_run, bool verbose) { int trylock = pthread_mutex_trylock( &queue->run_mutex ); if (trylock != 0) util_abort("%s: another thread is already running the queue_manager\n",__func__); else if (!queue->user_exit) { /* OK - we have got an exclusive lock to the run_jobs code. */ //Check if queue is open. Fails hard if not open job_queue_check_open(queue); /* The number of threads in the thread pool running callbacks. Memory consumption can potentially be quite high while running the DONE callback - should therefor not use too many threads. */ const int NUM_WORKER_THREADS = 4; queue->work_pool = thread_pool_alloc( NUM_WORKER_THREADS , true ); { bool new_jobs = false; bool cont = true; int phase = 0; queue->running = true; do { bool local_user_exit = false; job_list_get_rdlock( queue->job_list ); /*****************************************************************/ if (queue->user_exit) {/* An external thread has called the job_queue_user_exit() function, and we should kill all jobs, do some clearing up and go home. Observe that we will go through the queue handling codeblock below ONE LAST TIME before exiting. */ job_queue_user_exit__( queue ); local_user_exit = true; } job_queue_check_expired(queue); /*****************************************************************/ { bool update_status = job_queue_update_status( queue ); if (verbose) { if (update_status || new_jobs) job_queue_print_summary(queue , update_status ); job_queue_update_spinner( &phase ); } { int num_complete = job_queue_status_get_count(queue->status, JOB_QUEUE_SUCCESS) + job_queue_status_get_count(queue->status, JOB_QUEUE_FAILED) + job_queue_status_get_count(queue->status, JOB_QUEUE_IS_KILLED); if ((num_total_run > 0) && (num_total_run == num_complete)) /* The number of jobs completed is equal to the number of jobs we have said we want to run; so we are finished. */ cont = false; else { if (num_total_run == 0) { /* We have not informed about how many jobs we will run. To check if we are complete we perform the two tests: 1. All the jobs which have been added with job_queue_add_job() have completed. 2. The user has used job_queue_complete_submit() to signal that no more jobs will be forthcoming. */ if ((num_complete == job_list_get_size( queue->job_list )) && queue->submit_complete) cont = false; } } } if (cont) { /* Submitting new jobs */ int max_submit = 5; /* This is the maximum number of jobs submitted in one while() { ... } below. Only to ensure that the waiting time before a status update is not too long. */ int total_active = job_queue_status_get_count(queue->status, JOB_QUEUE_PENDING) + job_queue_status_get_count(queue->status, JOB_QUEUE_RUNNING); int num_submit_new; { int max_running = job_queue_get_max_running( queue ); if (max_running > 0) num_submit_new = util_int_min( max_submit , max_running - total_active ); else /* If max_running == 0 that should be interpreted as no limit; i.e. the queue layer will attempt to send an unlimited number of jobs to the driver - the driver can reject the jobs. */ num_submit_new = util_int_min( max_submit , job_queue_status_get_count(queue->status, JOB_QUEUE_WAITING)); } new_jobs = false; if (job_queue_status_get_count(queue->status, JOB_QUEUE_WAITING) > 0) /* We have waiting jobs at all */ if (num_submit_new > 0) /* The queue can allow more running jobs */ new_jobs = true; if (new_jobs) { int submit_count = 0; int queue_index = 0; while ((queue_index < job_list_get_size( queue->job_list )) && (num_submit_new > 0)) { job_queue_node_type * node = job_list_iget_job( queue->job_list , queue_index ); if (job_queue_node_get_status(node) == JOB_QUEUE_WAITING) { { submit_status_type submit_status = job_queue_submit_job(queue , queue_index); if (submit_status == SUBMIT_OK) { num_submit_new--; submit_count++; } else if ((submit_status == SUBMIT_DRIVER_FAIL) || (submit_status == SUBMIT_QUEUE_CLOSED)) break; } } queue_index++; } } { /* Checking for complete / exited / overtime jobs */ int queue_index; for (queue_index = 0; queue_index < job_list_get_size( queue->job_list ); queue_index++) { job_queue_node_type * node = job_list_iget_job( queue->job_list , queue_index ); switch (job_queue_node_get_status(node)) { case(JOB_QUEUE_DONE): job_queue_handle_DONE(queue, node); break; case(JOB_QUEUE_EXIT): job_queue_handle_EXIT(queue, node); break; case(JOB_QUEUE_DO_KILL_NODE_FAILURE): job_queue_handle_DO_KILL_NODE_FAILURE(queue, node); break; case(JOB_QUEUE_DO_KILL): job_queue_handle_DO_KILL(queue, node); break; default: break; } } } } else /* print an updated status to stdout before exiting. */ if (verbose) job_queue_print_summary(queue , true); } job_list_unlock( queue->job_list ); if (local_user_exit) cont = false; /* This is how we signal that we want to get out . */ else { util_yield(); job_list_reader_wait( queue->job_list , queue->usleep_time , 8 * queue->usleep_time); } } while ( cont ); } if (verbose) printf("\n"); thread_pool_join( queue->work_pool ); thread_pool_free( queue->work_pool ); } /* Set the queue's "open" flag to false to signal that the queue is not ready to be used in a new job_queue_run_jobs or job_queue_add_job method call as it has not been reset yet. Not resetting the queue here implies that the queue object is still available for queries after this method has finished */ queue->open = false; queue->running = false; pthread_mutex_unlock( &queue->run_mutex ); }
void enkf_tui_run_manual_load__( void * arg ) { enkf_main_type * enkf_main = enkf_main_safe_cast( arg ); enkf_fs_type * fs = enkf_main_get_fs( enkf_main ); const int last_report = -1; const int ens_size = enkf_main_get_ensemble_size( enkf_main ); int step1,step2; bool_vector_type * iactive = bool_vector_alloc( 0 , false ); run_mode_type run_mode = ENSEMBLE_EXPERIMENT; enkf_main_init_run(enkf_main , run_mode); /* This is ugly */ step1 = 0; step2 = last_report; /** Observe that for the summary data it will load all the available data anyway. */ { char * prompt = util_alloc_sprintf("Which realizations to load (Ex: 1,3-5) <Enter for all> [M to return to menu] : [ensemble size:%d] : " , ens_size); char * select_string; util_printf_prompt(prompt , PROMPT_LEN , '=' , "=> "); select_string = util_alloc_stdin_line(); enkf_tui_util_sscanf_active_list( iactive , select_string , ens_size ); util_safe_free( select_string ); free( prompt ); } if (bool_vector_count_equal( iactive , true )) { int iens; arg_pack_type ** arg_list = util_calloc( ens_size , sizeof * arg_list ); thread_pool_type * tp = thread_pool_alloc( 4 , true ); /* num_cpu - HARD coded. */ for (iens = 0; iens < ens_size; iens++) { arg_pack_type * arg_pack = arg_pack_alloc(); arg_list[iens] = arg_pack; if (bool_vector_iget(iactive , iens)) { enkf_state_type * enkf_state = enkf_main_iget_state( enkf_main , iens ); arg_pack_append_ptr( arg_pack , enkf_state); /* 0: */ arg_pack_append_ptr( arg_pack , fs ); /* 1: */ arg_pack_append_int( arg_pack , step1 ); /* 2: This will be the load start parameter for the run_info struct. */ arg_pack_append_int( arg_pack , step1 ); /* 3: Step1 */ arg_pack_append_int( arg_pack , step2 ); /* 4: Step2 For summary data it will load the whole goddamn thing anyway.*/ arg_pack_append_bool( arg_pack , true ); /* 5: Interactive */ arg_pack_append_owned_ptr( arg_pack , stringlist_alloc_new() , stringlist_free__); /* 6: List of interactive mode messages. */ thread_pool_add_job( tp , enkf_state_load_from_forward_model_mt , arg_pack); } } thread_pool_join( tp ); thread_pool_free( tp ); printf("\n"); { qc_module_type * qc_module = enkf_main_get_qc_module( enkf_main ); runpath_list_type * runpath_list = qc_module_get_runpath_list( qc_module ); for (iens = 0; iens < ens_size; iens++) { if (bool_vector_iget(iactive , iens)) { const enkf_state_type * state = enkf_main_iget_state( enkf_main , iens ); runpath_list_add( runpath_list , iens , enkf_state_get_run_path( state ) , enkf_state_get_eclbase( state )); } } qc_module_export_runpath_list( qc_module ); } for (iens = 0; iens < ens_size; iens++) { if (bool_vector_iget(iactive , iens)) { stringlist_type * msg_list = arg_pack_iget_ptr( arg_list[iens] , 6 ); if (stringlist_get_size( msg_list )) enkf_tui_display_load_msg( iens , msg_list ); } } for (iens = 0; iens < ens_size; iens++) arg_pack_free( arg_list[iens]); free( arg_list ); } bool_vector_free( iactive ); }
int main(int argc , char ** argv) { install_SIGNALS(); if(argc > 1) { if(strcmp(argv[1], "-h") == 0) print_usage(__LINE__); } if(argc < 2) print_usage(__LINE__); else{ char ** input = &argv[1]; /* Skipping the name of the executable */ int input_length = argc - 1; int input_offset = 0; bool use_eclbase, fmt_file; const char * report_filen = "RUN_GRAVITY.out"; ecl_file_type ** restart_files; ecl_file_type * init_file; ecl_grid_type * ecl_grid; int model_phases; int file_phases; vector_type * grav_stations = vector_alloc_new(); /* Restart info */ restart_files = load_restart_info( (const char **) input , input_length , &input_offset , &use_eclbase , &fmt_file); /* INIT and GRID/EGRID files */ { char * grid_filename = NULL; char * init_filename = NULL; if (use_eclbase) { /* The first command line argument is interpreted as ECLBASE, and we search for grid and init files in cwd. */ init_filename = ecl_util_alloc_exfilename_anyfmt( NULL , input[0] , ECL_INIT_FILE , fmt_file , -1); grid_filename = ecl_util_alloc_exfilename_anyfmt( NULL , input[0] , ECL_EGRID_FILE , fmt_file , -1); if (grid_filename == NULL) grid_filename = ecl_util_alloc_exfilename_anyfmt( NULL , input[0] , ECL_GRID_FILE , fmt_file , -1); if ((init_filename == NULL) || (grid_filename == NULL)) /* Means we could not find them. */ util_exit("Could not find INIT or GRID|EGRID file \n"); } else { /* */ if ((input_length - input_offset) > 1) { init_filename = util_alloc_string_copy(input[input_offset]); grid_filename = util_alloc_string_copy(input[input_offset + 1]); input_offset += 2; } else print_usage(__LINE__); } init_file = ecl_file_open(init_filename ); ecl_grid = ecl_grid_alloc(grid_filename ); free( init_filename ); free( grid_filename ); } // Load the station_file if (input_length > input_offset) { char * station_file = input[input_offset]; if (util_file_exists(station_file)) load_stations( grav_stations , station_file); else util_exit("Can not find file:%s \n",station_file); } else print_usage(__LINE__); /** OK - now everything is loaded - check that all required keywords+++ are present. */ gravity_check_input(ecl_grid , init_file , restart_files[0] , restart_files[1] , &model_phases , &file_phases); /* OK - now it seems the provided files have all the information we need. Let us start using it. The main loop is run in parallell on four threads - most people have four cores these days. */ { int i; int num_threads = 4; thread_pool_type * tp = thread_pool_alloc( num_threads , true); arg_pack_type ** arg_list = util_calloc( num_threads , sizeof * arg_list); { int station_delta = vector_get_size( grav_stations ) / num_threads; for (i = 0; i < num_threads; i++) { int station1 = i * station_delta; int station2 = station1 + station_delta; if (i == num_threads) station2 = vector_get_size( grav_stations ); arg_list[i] = arg_pack_alloc( ); arg_pack_append_ptr( arg_list[i] , grav_stations ); arg_pack_append_ptr( arg_list[i] , ecl_grid); arg_pack_append_ptr( arg_list[i] , init_file ); arg_pack_append_ptr( arg_list[i] , restart_files); arg_pack_append_int( arg_list[i] , station1 ); arg_pack_append_int( arg_list[i] , station2 ); arg_pack_append_int( arg_list[i] , model_phases ); arg_pack_append_int( arg_list[i] , file_phases ); thread_pool_add_job( tp , gravity_response_mt , arg_list[i]); } } thread_pool_join( tp ); for (i = 0; i < num_threads; i++) arg_pack_free( arg_list[i] ); free( arg_list ); } { FILE * stream = util_fopen(report_filen , "w"); int station_nr; double total_chisq = 0; for(station_nr = 0; station_nr < vector_get_size( grav_stations ); station_nr++){ const grav_station_type * g_s = vector_iget_const(grav_stations, station_nr); fprintf(stream, "%f",g_s->grav_diff); printf ("DELTA_G %4s[%02d]: %12.6f %12.6f %12.6f %12.6f", g_s->name , station_nr, g_s->grav_diff, g_s->utm_x, g_s->utm_y, g_s->depth); if ( g_s->has_obs ) { double y = (g_s->grav_diff - g_s->obs_gdiff) / g_s->std_gdiff; double chi_sq = y * y; total_chisq += chi_sq; fprintf(stream , " %g",chi_sq); printf(" %g",chi_sq); } fprintf(stream , " \n"); printf("\n"); } if (total_chisq > 0) { printf("Total chisq misfit: %g \n", total_chisq); } fclose(stream); } vector_free( grav_stations ); ecl_grid_free(ecl_grid); ecl_file_close(restart_files[0]); ecl_file_close(restart_files[1]); free( restart_files ); ecl_file_close(init_file); } }