int main (void) { FILE *f; char chem_file[] = "network.chm"; net_t network; int verbose = 1; /* Create the network.chm file */ f = fopen ("network.chm", "w"); fprintf (f, "# This network file was created by network test\n"); fprintf (f, "# The reaction were extracted form the OSU 2008 network\n"); fprintf (f, "H + H -> H2 4.95e-17 5.00e-01 0.00e+00 0 1\n"); fprintf (f, "C(+) + grain(-) -> C + grain 4.90e-17 5.00e-01 0.00e+00 0 3\n"); fprintf (f, "H3(+) + grain(-) -> H2 + H + grain 1.00e-16 5.00e-01 0.00e+00 0 13\n"); fprintf (f, "C + cosmic-ray -> C(+) + e(-) 1.02e+03 0.00e+00 0.00e+00 1 15\n"); fprintf (f, "CH5N + cosmic-ray -> HCN + H2 + H + H 1.41e+03 0.00e+00 0.00e+00 1 176\n"); fprintf (f, "C(+) + Fe -> Fe(+) + C 2.60e-09 0.00e+00 0.00e+00 2 218\n"); fprintf (f, "He(+) + HNC -> C(+) + N + H + He 4.43e-09 -5.00e-01 0.00e+00 2 735\n"); fprintf (f, "C(-) + NO -> CN(-) + O 1.00e-09 0.00e+00 0.00e+00 3 3151\n"); fprintf (f, "C(+) + H -> CH(+) 1.70e-17 0.00e+00 0.00e+00 4 3162\n"); fprintf (f, "C(-) + C -> C2 + e(-) 5.00e-10 0.00e+00 0.00e+00 5 3243\n"); fprintf (f, "O + CH -> HCO(+) + e(-) 2.00e-11 4.40e-01 0.00e+00 6 3289\n"); fprintf (f, "C + CH -> C2 + H 6.59e-11 0.00e+00 0.00e+00 7 3290\n"); fprintf (f, "C + C -> C2 + photon 1.00e-17 0.00e+00 0.00e+00 8 3672\n"); fprintf (f, "C2(+) + e(-) -> C + C 8.84e-08 -5.00e-01 0.00e+00 9 3688\n"); fprintf (f, "C(+) + e(-) -> C + photon 4.40e-12 -6.10e-01 0.00e+00 10 4227\n"); fprintf (f, "C(+) + C(-) -> C + C 2.30e-07 -5.00e-01 0.00e+00 11 4243\n"); fprintf (f, "C + e(-) -> C(-) 3.00e-15 0.00e+00 0.00e+00 12 4279\n"); fprintf (f, "O + -13-CH -> H-13-CO(+) + e(-) 2.00e-11 4.40e-01 0.00e+00 6 3289\n"); fprintf (f, "CO -> CO(ice) 1.00e+00 2.80e+01 0.00e+00 20 10044\n"); fclose (f); /* Read it */ if( read_network(chem_file, &network, verbose) != EXIT_SUCCESS ) { return EXIT_FAILURE; } /* Check that the values are correct */ if ((network.n_reactions == 19) && (network.n_species == 29) && /* Reaction #1 */ (network.reactions[0].reactants[0] == find_species("H", &network)) && (network.reactions[0].reactants[1] == find_species("H", &network)) && (network.reactions[0].reactants[2] == -1) && (network.reactions[0].products[0] == find_species("H2", &network)) && (network.reactions[0].products[1] == -1) && (network.reactions[0].products[2] == -1) && (network.reactions[0].products[3] == -1) && (network.reactions[0].alpha == 4.95e-17) && (network.reactions[0].beta == .5) && (network.reactions[0].gamma == 0) && (network.reactions[0].reaction_type == 0) && (network.reactions[0].reaction_no == 1) && /* Reaction #176 */ (network.reactions[4].reactants[0] == find_species("CH5N", &network)) && (network.reactions[4].reactants[1] == -1) && (network.reactions[4].reactants[2] == -1) && (network.reactions[4].products[0] == find_species("HCN", &network)) && (network.reactions[4].products[1] == find_species("H2", &network)) && (network.reactions[4].products[2] == find_species("H", &network)) && (network.reactions[4].products[3] == find_species("H", &network) )&& (network.reactions[4].alpha == 1.41e3) && (network.reactions[4].beta == 0) && (network.reactions[4].gamma == 0) && (network.reactions[4].reaction_type == 1) && (network.reactions[4].reaction_no == 176) && /* Reaction #4227 */ (network.reactions[14].reactants[0] == find_species("C(+)", &network) )&& (network.reactions[14].reactants[1] == find_species("e(-)", &network) )&& (network.reactions[14].reactants[2] == -1) && (network.reactions[14].products[0] == find_species("C", &network) )&& (network.reactions[14].products[1] == -1) && (network.reactions[14].products[2] == -1) && (network.reactions[14].products[3] == -1) && (network.reactions[14].alpha == 4.40e-12) && (network.reactions[14].beta == -.61) && (network.reactions[14].gamma == 0) && (network.reactions[14].reaction_type == 10) && (network.reactions[14].reaction_no == 4227) && /* Mass and charge of a few species */ (abs(network.species[find_species("C(+)", &network)].mass / UMA - 12) <= 0.01) && (network.species[find_species("C(+)", &network)].charge == 1.0) && (abs(network.species[find_species("HCO(+)", &network)].mass / UMA - 29) <= 0.01) && (network.species[find_species("HCO(+)", &network)].charge == 1.0) && (abs(network.species[find_species("H-13-CO(+)", &network)].mass / UMA - 30) <= 0.01) && (network.species[find_species("H-13-CO(+)", &network)].charge == 1.0) && (abs(network.species[find_species("CH5N", &network)].mass / UMA - 31) <= 0.01) && (network.species[find_species("CH5N", &network)].charge == 0.0) && (network.species[find_species("e(-)", &network)].charge == -1)) { free_network (&network); return EXIT_SUCCESS; } else { free_network (&network); return EXIT_FAILURE; } }
int full_solve (hid_t fid, hid_t dataset, hid_t* routeDatasets, hid_t dataspace, hid_t routeDataspace, hid_t datatype, hid_t routeDatatype, int cell_index, const inp_t * input_params, SOURCE_MODE mode, const cell_table_t * cell, const net_t * network, const time_steps_t * ts, int verbose) { double *abundances = NULL; alloc_abundances( network, &abundances ); // Allocate the abundances array; it contains all species. rout_t* routes = NULL; if (( routes = malloc (sizeof (rout_t) * input_params->output.n_output_species * N_OUTPUT_ROUTES)) == NULL) { fprintf (stderr, "astrochem: %s:%d: routes allocation failed.\n", __FILE__, __LINE__); return EXIT_SUCCESS; } double* output_abundances = NULL; if (( output_abundances = malloc (sizeof (double) * input_params->output.n_output_species )) == NULL) { fprintf (stderr, "astrochem: %s:%d: array allocation failed.\n", __FILE__, __LINE__); return EXIT_FAILURE; } #ifdef HAVE_OPENMP omp_set_lock(&lock); #endif // Create the memory dataspace, selecting all output abundances hsize_t size = input_params->output.n_output_species; hid_t memDataspace = H5Screate_simple(1, &size, NULL); // Create the file dataspace, and prepare selection of a chunk of the file hid_t fileDataspace = H5Scopy(dataspace); hsize_t count[3]={ 1, 1, input_params->output.n_output_species }; hsize_t routeSize[2] = { input_params->output.n_output_species, N_OUTPUT_ROUTES }; hsize_t routeCount[4]={ 1, 1, input_params->output.n_output_species, N_OUTPUT_ROUTES }; hid_t routeFileDataspace, routeMemDataspace; if (input_params->output.trace_routes) { // Create the route memory dataspace, selecting all output routes routeMemDataspace = H5Screate_simple(2, routeSize, NULL); // Create the route file dataspace, and prepare selection of a chunk of the file routeFileDataspace = H5Scopy(routeDataspace); } #ifdef HAVE_OPENMP omp_unset_lock(&lock); #endif // Initializing abundance #if 0 //Ultra complicated code const species_name_t* species = malloc( input_params->abundances.n_initial_abundances * sizeof(*species)); double *initial_abundances = malloc( input_params->abundances.n_initial_abundances * sizeof(double) ); int i; for( i = 0; i < input_params->abundances.n_initial_abundances ; i++ ) { strcpy( network->species_names[input_params->abundances.initial_abundances[i].species_idx ] , species[i] ); initial_abundances[i] = input_params->abundances.initial_abundances[i].abundance; } set_initial_abundances( species, 3, initial_abundances, &network, abundances); // Set initial abundances #else // same thing , without using api int i; for( i = 0; i < input_params->abundances.n_initial_abundances ; i++ ) { abundances[ input_params->abundances.initial_abundances[i].species_idx ] = input_params->abundances.initial_abundances[i].abundance; } // Add grain abundances int g, gm, gp; double gabs; g = find_species ("grain", network); gm = find_species ("grain(-)", network); gp = find_species ("grain(+)", network); // Check if grain abundances have already been initialized one way or another gabs=0.0; if(g>=0) gabs += abundances[ g ]; if(gm>=0) gabs += abundances[ gm ]; if(gp>=0) gabs += abundances[ gp ]; if(gabs == 0.0) { // Grains have not been initialized // Check that grains are defined in our network, and if so, set the grain abundance if(g>=0) abundances[ g ] = input_params->phys.grain_abundance; } #endif double min_nh; /* Minimum density */ /* Compute the minimum density to set the absolute tolerance of the solver */ min_nh = cell->nh[0]; if (mode == DYNAMIC) { int i; for (i = 1; i < ts->n_time_steps; i++) { if (cell->nh[i] < min_nh) { min_nh = cell->nh[i]; } } } astrochem_mem_t astrochem_mem; cell_t cell_unik; cell_unik.av = cell->av[0]; cell_unik.nh = cell->nh[0]; cell_unik.tgas = cell->tgas[0]; cell_unik.tdust = cell->tdust[0]; if( solver_init( &cell_unik, network, &input_params->phys, abundances, min_nh, input_params->solver.abs_err, input_params->solver.rel_err, &astrochem_mem ) != EXIT_SUCCESS ) { return EXIT_FAILURE; } else { int i, j; /* Solve the system for each time step. */ for (i = 0; i < ts->n_time_steps; i++) { if (i!=0 && mode == DYNAMIC) { cell_unik.av = cell->av[i]; cell_unik.nh = cell->nh[i]; cell_unik.tgas = cell->tgas[i]; cell_unik.tdust = cell->tdust[i]; if( solve( &astrochem_mem, network, abundances, ts->time_steps[i], &cell_unik, verbose ) != EXIT_SUCCESS ) { return EXIT_FAILURE; } } else { if( solve( &astrochem_mem, network, abundances, ts->time_steps[i], NULL, verbose ) != EXIT_SUCCESS ) { return EXIT_FAILURE; } } /* Fill the array of abundances with the output species abundances. Ignore species that are not in the network. Abundance that are lower than MIN_ABUNDANCES are set to 0. */ for (j = 0; j < input_params->output.n_output_species; j++) { if (mode == STATIC) { output_abundances[j] = (double) NV_Ith_S (astrochem_mem.y, input_params->output.output_species_idx[j]) / cell->nh[0]; } else { output_abundances[j] = (double) NV_Ith_S (astrochem_mem.y, input_params->output.output_species_idx[j]) / cell->nh[i]; } if (output_abundances[j] < MIN_ABUNDANCE) output_abundances[j] = 0.; #ifdef HAVE_OPENMP omp_set_lock(&lock); #endif // Select a chunk of the file hsize_t start[3]={ cell_index, i, 0 }; H5Sselect_hyperslab( fileDataspace, H5S_SELECT_SET, start, NULL, count , NULL ); // Write the chunk H5Dwrite(dataset, datatype, memDataspace, fileDataspace, H5P_DEFAULT, output_abundances ); #ifdef HAVE_OPENMP omp_unset_lock(&lock); #endif } /* Compute the rate of each formation/destruction route for each output specie. */ if (input_params->output.trace_routes) { for (j = 0; j < input_params->output.n_output_species; j++) { int k; int l; for (l = 0; l < N_OUTPUT_ROUTES; l++) { routes[ j*N_OUTPUT_ROUTES + l ].formation.rate = 0; routes[ j*N_OUTPUT_ROUTES + l ].destruction.rate = 0; } for (k = 0; k < network->n_reactions; k++) { /* If the species is a product of the reaction then compute the formation rate. If the rate is greater than the smallest rate in the formation route structure, we add the current reaction number and rate to that structure. */ bool specie_in_products = false; int p; for( p = 0; p < MAX_PRODUCTS; p++ ) { if( network->reactions[k].products[p] == input_params->output.output_species_idx[j]) { specie_in_products = true; break; } } if( specie_in_products ) { r_t formation_route; double min_rate; unsigned int min_rate_index; if (network->reactions[k].reaction_type == 0) { formation_route.rate = astrochem_mem.params.reac_rates[k]; formation_route.rate *= NV_Ith_S (astrochem_mem.y, network->reactions[k].reactants[0]); } else if (network->reactions[k].reaction_type == 23) { formation_route.rate = astrochem_mem.params.reac_rates[k]; } else { formation_route.rate = astrochem_mem.params.reac_rates[k]; int r; for( r = 0; r < MAX_REACTANTS; r++ ) { if( network->reactions[k].reactants[r] != -1 ) { formation_route.rate *= NV_Ith_S (astrochem_mem.y, network->reactions[k].reactants[r]); } } } formation_route.reaction_no = network->reactions[k].reaction_no; min_rate = routes[ j*N_OUTPUT_ROUTES ].formation.rate; min_rate_index = 0; for (l = 1; l < N_OUTPUT_ROUTES; l++) { if (routes[ j*N_OUTPUT_ROUTES + l ].formation.rate < min_rate) { min_rate = routes[ j*N_OUTPUT_ROUTES + l ].formation.rate; min_rate_index = (unsigned int) l; } } if (formation_route.rate > min_rate) { routes[ j*N_OUTPUT_ROUTES + min_rate_index ].formation.rate = formation_route.rate; routes[ j*N_OUTPUT_ROUTES + min_rate_index ].formation.reaction_no = formation_route.reaction_no; } } /* If the species is reactant of the reaction then compute the destruction rate. */ bool species_in_reactants = false; int r; for ( r = 0; r < MAX_REACTANTS; r++ ) { if ( network->reactions[k].reactants[r] == input_params->output.output_species_idx[j]) { species_in_reactants = true; break; } } if( species_in_reactants ) { r_t destruction_route; double min_rate; unsigned int min_rate_index; if (network->reactions[k].reaction_type == 0) { destruction_route.rate = astrochem_mem.params.reac_rates[k]; destruction_route.rate *= NV_Ith_S (astrochem_mem.y, network->reactions[k].reactants[0]); } else if (network->reactions[k].reaction_type == 23) { destruction_route.rate = astrochem_mem.params.reac_rates[k]; } else { destruction_route.rate = astrochem_mem.params.reac_rates[k]; for ( r = 0; r < MAX_REACTANTS; r++ ) { if (network->reactions[k].reactants[r] != -1) { destruction_route.rate *= NV_Ith_S (astrochem_mem.y, network->reactions[k].reactants[r]); } } } destruction_route.reaction_no = network->reactions[k].reaction_no; min_rate = routes[ j*N_OUTPUT_ROUTES ].destruction.rate; min_rate_index = 0; for (l = 1; l < N_OUTPUT_ROUTES; l++) { if (routes[ j*N_OUTPUT_ROUTES + l ].destruction.rate < min_rate) { min_rate = routes[ j*N_OUTPUT_ROUTES + l ].destruction.rate; min_rate_index = (unsigned int) l; } } if (destruction_route.rate > min_rate) { routes[ j*N_OUTPUT_ROUTES + min_rate_index ].destruction.rate = destruction_route.rate; routes[ j*N_OUTPUT_ROUTES + min_rate_index ].destruction.reaction_no = destruction_route.reaction_no; } } } } #ifdef HAVE_OPENMP omp_set_lock(&lock); #endif // Selecting a chunk of the file hsize_t routeStart[4]={ cell_index, i, 0, 0 }; H5Sselect_hyperslab( routeFileDataspace, H5S_SELECT_SET, routeStart, NULL, routeCount , NULL ); int spec_idx; for( spec_idx = 0; spec_idx < input_params->output.n_output_species; spec_idx++ ) { // Writing in each route datasets H5Dwrite( routeDatasets[ spec_idx ], routeDatatype, routeMemDataspace, routeFileDataspace, H5P_DEFAULT, routes ); } #ifdef HAVE_OPENMP omp_unset_lock(&lock); #endif } } } #ifdef HAVE_OPENMP omp_set_lock(&lock); #endif // Cleaning up hdf5 H5Sclose(memDataspace); H5Sclose(fileDataspace); if (input_params->output.trace_routes) { H5Sclose(routeMemDataspace); H5Sclose(routeFileDataspace); } #ifdef HAVE_OPENMP omp_unset_lock(&lock); #endif // Free free( output_abundances ); free( routes ); free_abundances( abundances ); solver_close( &astrochem_mem ); return EXIT_SUCCESS; }