void Input_CreateAlquimiaInterface(const char* input_file, AlquimiaInterface* engine_interface, AlquimiaSizes* engine_sizes, AlquimiaEngineFunctionality* engine_functionality, AlquimiaEngineStatus* engine_status) { // Get the engine and other parameters. EngineData data; int error = ini_parse(input_file, ParseEngineData, &data); if (error != 0) alquimia_error("Input_CreateAlqumiaInterface: Error parsing input: %s", input_file); // Initialize the engine. CreateAlquimiaInterface(data.engine_name, engine_interface, engine_status); if (engine_status->error != 0) alquimia_error("Input_CreateAlquimiaInterface: %s", engine_status->message); // Set it up with our parameters and retrieve functionality. engine_interface->Setup(data.input_file, data.hands_off, engine_interface, engine_sizes, engine_functionality, engine_status); if (engine_status->error != 0) alquimia_error("Input_CreateAlquimiaInterface: %s", engine_status->message); }
void Input_GetRegions(const char* input_file, AlquimiaVectorString* region_names) { int error = ini_parse(input_file, ParseRegionName, region_names); if (error != 0) alquimia_error("Input_GetRegions: Error parsing input: %s", input_file); }
int main(int argc, char* argv[]) { if (argc == 1) Usage(); // Initialize PETSc/MPI for command line options and engines that // require it. char help[] = "Alquimia advective, nondispersive reactive transport driver"; PetscInitialize(&argc, &argv, (char*)0, help); PetscInitializeFortran(); char input_file[FILENAME_MAX]; strncpy(input_file, argv[1], FILENAME_MAX-1); // Parse the input file. TransportDriverInput* input = TransportDriverInput_New(input_file); if (input == NULL) alquimia_error("transport: error encountered reading input file '%s'.", input_file); // Set up output. DriverOutput* output = NULL; if (AlquimiaCaseInsensitiveStringCompare(input->output_type, "python")) output = PythonDriverOutput_New(); else if (AlquimiaCaseInsensitiveStringCompare(input->output_type, "gnuplot")) output = GnuplotDriverOutput_New(); // Create a TransportDriver from the parsed input. TransportDriver* transport = TransportDriver_New(input); // Run the simulation. int status = TransportDriver_Run(transport); // Get the solution out of the driver and write it out. if (output != NULL) { double final_time; AlquimiaVectorString var_names = {.size = 0}; AlquimiaVectorDouble var_data = {.size = 0}; TransportDriver_GetSoluteAndAuxData(transport, &final_time, &var_names, &var_data); DriverOutput_WriteMulticompVector(output, input->output_file, var_names, var_data); FreeAlquimiaVectorString(&var_names); FreeAlquimiaVectorDouble(&var_data); } // Clean up. TransportDriverInput_Free(input); TransportDriver_Free(transport); PetscInt petsc_error = PetscFinalize(); if (status == EXIT_SUCCESS && petsc_error == 0) printf("Success!\n"); else printf("Failed!\n"); return status; }
void DriverOutput_WriteVectors(DriverOutput* output, const char* filename, AlquimiaVectorString var_names, AlquimiaVectorDouble* var_vectors) { if (var_names.size == 0) alquimia_error("DriverOutput_WriteVectors: no variables to write!"); for (int i = 1; i < var_names.size; ++i) { if (var_vectors[i].size != var_vectors[0].size) { alquimia_error("DriverOutput_WriteVectors: vector %d has %d data, but vector 0 has %d.", i, var_vectors[i].size, var_vectors[0].size); } } FILE* file = fopen(filename, "w"); output->Write(var_names, var_vectors, file); fclose(file); }
void DriverOutput_WriteMulticompVector(DriverOutput* output, const char* filename, AlquimiaVectorString comp_names, AlquimiaVectorDouble multicomp_vector) { int num_comps = comp_names.size; if ((multicomp_vector.size % num_comps) != 0) { alquimia_error("DriverOutput_WriteMulticompVector: multicomp_vector data has invalid size for %d components (%d).", num_comps, multicomp_vector.size); } int vec_size = multicomp_vector.size / num_comps; AlquimiaVectorDouble var_vectors[num_comps]; for (int i = 0; i < num_comps; ++i) { AllocateAlquimiaVectorDouble(vec_size, &var_vectors[i]); for (int j = 0; j < vec_size; ++j) var_vectors[i].data[j] = multicomp_vector.data[num_comps*j+i]; } DriverOutput_WriteVectors(output, filename, comp_names, var_vectors); for (int i = 0; i < num_comps; ++i) FreeAlquimiaVectorDouble(&var_vectors[i]); }
static int Run_GlobalImplicit(TransportDriver* driver) { alquimia_error("Globally implicit transport is not yet supported."); return -1; }
TransportDriver* TransportDriver_New(TransportDriverInput* input) { TransportDriver* driver = malloc(sizeof(TransportDriver)); // Get basic simulation parameters. driver->description = AlquimiaStringDup(input->description); driver->coupling = input->coupling; driver->t_min = input->t_min; driver->t_max = input->t_max; driver->max_steps = input->max_steps; driver->dt = input->dt; driver->cfl = input->cfl_factor; driver->verbose = input->verbose; // Get grid information. driver->x_min = input->x_min; driver->x_max = input->x_max; driver->num_cells = input->num_cells; // Get material properties. driver->porosity = input->porosity; driver->saturation = input->saturation; // Get flow variables. driver->vx = input->velocity; driver->temperature = input->temperature; // Simulation state. driver->time = driver->t_min; driver->step = 0; // Set up the chemistry engine. AllocateAlquimiaEngineStatus(&driver->chem_status); CreateAlquimiaInterface(input->chemistry_engine, &driver->chem, &driver->chem_status); if (driver->chem_status.error != 0) { alquimia_error("TransportDriver_New: %s", driver->chem_status.message); return NULL; } // Set up the engine and get storage requirements. AlquimiaEngineFunctionality chem_engine_functionality; driver->chem.Setup(input->chemistry_input_file, input->hands_off, &driver->chem_engine, &driver->chem_sizes, &chem_engine_functionality, &driver->chem_status); if (driver->chem_status.error != 0) { alquimia_error("TransportDriver_New: %s", driver->chem_status.message); return NULL; } // If you want multiple copies of the chemistry engine with // OpenMP, verify: chem_data.functionality.thread_safe == true, // then create the appropriate number of chem status and data // objects. // Allocate memory for the chemistry data. AllocateAlquimiaProblemMetaData(&driver->chem_sizes, &driver->chem_metadata); driver->chem_properties = malloc(sizeof(AlquimiaProperties) * driver->num_cells); driver->chem_state = malloc(sizeof(AlquimiaState) * driver->num_cells); driver->chem_aux_data = malloc(sizeof(AlquimiaAuxiliaryData) * driver->num_cells); driver->chem_aux_output = malloc(sizeof(AlquimiaAuxiliaryOutputData) * driver->num_cells); for (int i = 0; i < driver->num_cells; ++i) { AllocateAlquimiaState(&driver->chem_sizes, &driver->chem_state[i]); AllocateAlquimiaProperties(&driver->chem_sizes, &driver->chem_properties[i]); AllocateAlquimiaAuxiliaryData(&driver->chem_sizes, &driver->chem_aux_data[i]); AllocateAlquimiaAuxiliaryOutputData(&driver->chem_sizes, &driver->chem_aux_output[i]); } // Metadata. driver->chem.GetProblemMetaData(&driver->chem_engine, &driver->chem_metadata, &driver->chem_status); if (driver->chem_status.error != 0) { alquimia_error("TransportDriver_New: %s", driver->chem_status.message); return NULL; } // Initial condition. AllocateAlquimiaGeochemicalCondition(strlen(input->ic_name), 0, 0, &driver->chem_ic); strcpy(driver->chem_ic.name, input->ic_name); // Boundary conditions. if (input->left_bc_name != NULL) { AllocateAlquimiaGeochemicalCondition(strlen(input->left_bc_name), 0, 0, &driver->chem_left_bc); strcpy(driver->chem_left_bc.name, input->left_bc_name); } AllocateAlquimiaState(&driver->chem_sizes, &driver->chem_left_state); AllocateAlquimiaAuxiliaryData(&driver->chem_sizes, &driver->chem_left_aux_data); if (input->right_bc_name != NULL) { AllocateAlquimiaGeochemicalCondition(strlen(input->right_bc_name), 0, 0, &driver->chem_right_bc); strcpy(driver->chem_right_bc.name, input->right_bc_name); } AllocateAlquimiaState(&driver->chem_sizes, &driver->chem_right_state); AllocateAlquimiaAuxiliaryData(&driver->chem_sizes, &driver->chem_right_aux_data); // Copy the miscellaneous chemistry state information in. // NOTE: For now, we only allow one of each of these reactions. for (int i = 0; i < driver->num_cells; ++i) { for (int j = 0; j < driver->chem_state[i].cation_exchange_capacity.size; ++j) driver->chem_state[i].cation_exchange_capacity.data[j] = input->cation_exchange_capacity; for (int j = 0; j < driver->chem_state[i].surface_site_density.size; ++j) driver->chem_state[i].surface_site_density.data[j] = input->surface_site_density; } for (int j = 0; j < driver->chem_left_state.cation_exchange_capacity.size; ++j) driver->chem_left_state.cation_exchange_capacity.data[j] = input->cation_exchange_capacity; for (int j = 0; j < driver->chem_left_state.surface_site_density.size; ++j) driver->chem_left_state.surface_site_density.data[j] = input->surface_site_density; for (int j = 0; j < driver->chem_right_state.cation_exchange_capacity.size; ++j) driver->chem_right_state.cation_exchange_capacity.data[j] = input->cation_exchange_capacity; for (int j = 0; j < driver->chem_right_state.surface_site_density.size; ++j) driver->chem_right_state.surface_site_density.data[j] = input->surface_site_density; // Bookkeeping. AllocateAlquimiaState(&driver->chem_sizes, &driver->advected_chem_state); AllocateAlquimiaAuxiliaryData(&driver->chem_sizes, &driver->advected_chem_aux_data); driver->advective_fluxes = malloc(sizeof(double) * driver->chem_sizes.num_primary * (driver->num_cells + 1)); return driver; }
TransportDriverInput* TransportDriverInput_New(const char* input_file) { TransportDriverInput* input = malloc(sizeof(TransportDriverInput)); memset(input, 0, sizeof(TransportDriverInput)); // Make sure we have some meaningful defaults. input->hands_off = true; // Hands-off by default. input->t_min = 0.0; input->max_steps = INT_MAX; input->dt = FLT_MAX; input->cfl_factor = 1.0; input->porosity = 1.0; input->saturation = 1.0; input->temperature = 25.0; input->velocity = 0.0; input->left_bc_name = NULL; input->right_bc_name = NULL; input->cation_exchange_capacity = 0.0; input->surface_site_density = 0.0; input->output_type = NULL; input->output_file = NULL; // Fill in fields by parsing the input file. int error = ini_parse(input_file, ParseInput, input); if (error != 0) { TransportDriverInput_Free(input); alquimia_error("TransportDriver: Error parsing input: %s", input_file); } // Verify that our required fields are filled properly. if (!input->hands_off) alquimia_error("TransportDriver: simulation->hands_off must be set to true at the moment."); if (input->t_max <= input->t_min) alquimia_error("TransportDriver: simulation->t_max must be greater than simulation->t_min."); if (input->max_steps < 0) alquimia_error("TransportDriver: simulation->max_steps must be non-negative."); if ((input->cfl_factor <= 0.0) || (input->cfl_factor > 1.0)) alquimia_error("TransportDriver: simulation->cfl_factor must be within (0, 1]."); if (input->x_max <= input->x_min) alquimia_error("TransportDriver: domain->x_max must be greater than domain->x_min."); if (input->num_cells <= 0) alquimia_error("TransportDriver: domain->num_cells must be positive."); if ((input->porosity <= 0.0) || (input->porosity > 1.0)) alquimia_error("TransportDriver: material->porosity must be within (0, 1]."); if ((input->saturation <= 0.0) || (input->saturation > 1.0)) alquimia_error("TransportDriver: material->saturation must be within (0, 1]."); if (input->temperature <= 0.0) alquimia_error("TransportDriver: flow->temperature must be positive."); if ((input->left_bc_name == NULL) && (input->right_bc_name == NULL) && (input->velocity != 0.0)) alquimia_error("TransportDriver: When velocity != 0, left or right boundary condition must be given."); // Default output. if (input->output_type == NULL) input->output_type = AlquimiaStringDup("gnuplot"); char default_output_file[FILENAME_MAX]; if (input->output_file == NULL) { // Find the last '.' in the input filename. int dot = strlen(input_file)-1; while ((dot > 0) && (input_file[dot] != '.')) --dot; char suffix[16]; // Determine the suffix from the output type. if (AlquimiaCaseInsensitiveStringCompare(input->output_type, "gnuplot")) sprintf(suffix, ".gnuplot"); else if (AlquimiaCaseInsensitiveStringCompare(input->output_type, "python")) sprintf(suffix, ".py"); // Append the suffix. if (dot == 0) sprintf(default_output_file, "%s%s", input_file, suffix); else { memcpy(default_output_file, input_file, sizeof(char) * dot); strcat(default_output_file, suffix); } // Python modules can't have hyphens in their names, so we replace them // with underscores. if (AlquimiaCaseInsensitiveStringCompare(input->output_type, "python")) { int len = strlen(default_output_file); for (int i = 0; i < len; ++i) { if (default_output_file[i] == '-') default_output_file[i] = '_'; } } input->output_file = AlquimiaStringDup(default_output_file); } return input; }