void FreeAlquimiaProperties(AlquimiaProperties* props) { if (props != NULL) { FreeAlquimiaVectorDouble(&(props->isotherm_kd)); FreeAlquimiaVectorDouble(&(props->freundlich_n)); FreeAlquimiaVectorDouble(&(props->langmuir_b)); FreeAlquimiaVectorDouble(&(props->mineral_rate_cnst)); FreeAlquimiaVectorDouble(&(props->aqueous_kinetic_rate_cnst)); } } /* end FreeAlquimiaProperties() */
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 FreeAlquimiaAuxiliaryOutputData(AlquimiaAuxiliaryOutputData* aux_output) { if (aux_output != NULL) { FreeAlquimiaVectorDouble(&(aux_output->aqueous_kinetic_rate)); FreeAlquimiaVectorDouble(&(aux_output->mineral_saturation_index)); FreeAlquimiaVectorDouble(&(aux_output->mineral_reaction_rate)); FreeAlquimiaVectorDouble(&(aux_output->primary_free_ion_concentration)); FreeAlquimiaVectorDouble(&(aux_output->primary_activity_coeff)); FreeAlquimiaVectorDouble(&(aux_output->secondary_free_ion_concentration)); FreeAlquimiaVectorDouble(&(aux_output->secondary_activity_coeff)); } } /* end FreeAlquimiaAuxiliaryOutputData() */
void FreeAlquimiaState(AlquimiaState* state) { if (state != NULL) { FreeAlquimiaVectorDouble(&(state->total_mobile)); FreeAlquimiaVectorDouble(&(state->total_immobile)); FreeAlquimiaVectorDouble(&(state->mineral_volume_fraction)); FreeAlquimiaVectorDouble(&(state->mineral_specific_surface_area)); FreeAlquimiaVectorDouble(&(state->cation_exchange_capacity)); FreeAlquimiaVectorDouble(&(state->surface_site_density)); } } /* end FreeAlquimiaState() */
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]); }
void TransportDriver_GetSoluteAndAuxData(TransportDriver* driver, double* time, AlquimiaVectorString* var_names, AlquimiaVectorDouble* var_data) { // Destroy the contents of the vectors we're given. if (var_names->size > 0) FreeAlquimiaVectorString(var_names); if (var_data->size > 0) FreeAlquimiaVectorDouble(var_data); // Construct a list of all variables, which are those in the state and // the auxiliary output data, and fill their data. int num_cells = driver->num_cells; int num_primary = driver->chem_sizes.num_primary; int num_sorbed = driver->chem_sizes.num_sorbed; int num_minerals = driver->chem_sizes.num_minerals; int num_surface_sites = driver->chem_sizes.num_surface_sites; int num_ion_exchange_sites = driver->chem_sizes.num_ion_exchange_sites; int num_aqueous_complexes = driver->chem_sizes.num_aqueous_complexes; int num_aqueous_kinetics = driver->chem_sizes.num_aqueous_kinetics; int num_vars = 1 + // grid cell locations num_primary + // total mobile num_sorbed + // total immobile 2 * num_minerals + // mineral volume fractions, specific surface area num_surface_sites + // surface site density num_ion_exchange_sites + // cation exchange capacity 1 + // pH num_aqueous_kinetics + // aqueous kinetic rate 2 * num_minerals + // mineral saturation index, reaction rate 2 * num_primary + // primary free ion concentration, activity coeff 2 * num_aqueous_complexes; // secondary free ion concentration, activity coeff int counter = 0; AllocateAlquimiaVectorString(num_vars, var_names); AllocateAlquimiaVectorDouble(num_vars * driver->num_cells, var_data); { var_names->data[counter] = AlquimiaStringDup("x"); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->x_min + (j+0.5) * (driver->x_max - driver->x_min) / driver->num_cells; ++counter; } for (int i = 0; i < num_primary; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "total_mobile[%s]", driver->chem_metadata.primary_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_state[j].total_mobile.data[i]; } for (int i = 0; i < num_sorbed; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "total_immobile[%d]", i); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_state[j].total_immobile.data[i]; } for (int i = 0; i < num_minerals; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "mineral_volume_fractions[%s]", driver->chem_metadata.mineral_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_state[j].mineral_volume_fraction.data[i]; } for (int i = 0; i < num_minerals; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "mineral_specific_surface_area[%s]", driver->chem_metadata.mineral_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_state[j].mineral_specific_surface_area.data[i]; } for (int i = 0; i < num_surface_sites; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "surface_site_density[%s]", driver->chem_metadata.surface_site_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_state[j].surface_site_density.data[i]; } for (int i = 0; i < num_ion_exchange_sites; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "cation_exchange_capacity[%s]", driver->chem_metadata.ion_exchange_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_state[j].cation_exchange_capacity.data[i]; } { var_names->data[counter] = AlquimiaStringDup("pH"); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].pH; ++counter; } for (int i = 0; i < num_aqueous_kinetics; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "aqueous_kinetic_rate[%s]", driver->chem_metadata.aqueous_kinetic_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].aqueous_kinetic_rate.data[i]; } for (int i = 0; i < num_minerals; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "mineral_saturation_index[%s]", driver->chem_metadata.mineral_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].mineral_saturation_index.data[i]; } for (int i = 0; i < num_minerals; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "mineral_reaction_rate[%s]", driver->chem_metadata.mineral_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].mineral_reaction_rate.data[i]; } for (int i = 0; i < num_primary; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "primary_free_ion_concentration[%s]", driver->chem_metadata.primary_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].primary_free_ion_concentration.data[i]; } for (int i = 0; i < num_primary; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "primary_activity_coeff[%s]", driver->chem_metadata.primary_names.data[i]); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].primary_activity_coeff.data[i]; } for (int i = 0; i < num_aqueous_complexes; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "secondary_free_ion_concentration[%d]", i); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].secondary_free_ion_concentration.data[i]; } for (int i = 0; i < num_aqueous_complexes; ++i, ++counter) { char var_name[1024]; snprintf(var_name, 1023, "secondary_activity_coeff[%d]", i); var_names->data[counter] = AlquimiaStringDup(var_name); for (int j = 0; j < num_cells; ++j) var_data->data[num_vars*j + counter] = driver->chem_aux_output[j].secondary_activity_coeff.data[i]; } }
void FreeAlquimiaAuxiliaryData(AlquimiaAuxiliaryData* aux_data) { if (aux_data != NULL) { FreeAlquimiaVectorInt(&(aux_data->aux_ints)); FreeAlquimiaVectorDouble(&(aux_data->aux_doubles)); } } /* end FreeAlquimiaAuxiliaryData() */