void bc_matrl_index(Exo_DB *exo) /******************************************************************** * * bc_matrl_index(): * * Find out what materials are on each side of a boundary * condition. Note, some boundary conditions require one * to specify this information in the form of an element block * id. However, some others do not. This procedure attempts to * calculate this for all boundary conditions and then fill in * the BC_matrl_index_# elements of the Boundary_Condition * structure. * * The basic algorithm involves finding some information about * the side or node set on which the boundary condition is * applied. Then, given the bc name and this information, * a decision is made as to what the BC_matrl_index_#'s should be * set to. * * We gather the following information to make this decision: * 1) element block indecises input from deck * 2) Number of nodes in the bc set in each material * 3) Number of elements, whoses sides are in the side set, * in each material * 4) Node in the bc set which contains the minimum * number of materials * 5) Node in the bc set which contains the maximum * number of materials * 6) A random node in the bc set which contains a * specific number of materials (1, 2, 3, 4) * * * HKM NOTE: * This routine is a work in progress. Calculation of EDGE's and * VERTICES are not done yet. Also, mp aspects haven't been * figured out yet. * *******************************************************************/ { int ibc, ss_index, side_index, k, node_num, i; int i_apply_meth, num_matrl_needed = -1; int found = FALSE, min_node_matrl, max_node_matrl, min_matrl, max_matrl, node_matrl_1, node_matrl_2, node_matrl_3, node_matrl_4, matrl_first; int *bin_matrl, *ind_matrl, *bin_matrl_elem, *node_flag_1ss, node_count; int mat_index, success, ielem; NODE_INFO_STRUCT *node_ptr; UMI_LIST_STRUCT *matrlLP; struct Boundary_Condition *bc_ptr; static char *yo = "bc_matrl_index :"; bin_matrl = alloc_int_1(upd->Num_Mat * 4, INT_NOINIT); ind_matrl = bin_matrl + upd->Num_Mat; bin_matrl_elem = ind_matrl + upd->Num_Mat; node_flag_1ss = alloc_int_1(exo->num_nodes, INT_NOINIT); for (ibc = 0; ibc < Num_BC; ibc++) { bc_ptr = BC_Types + ibc; found = FALSE; /* * Some boundary condition specifications already require * you to specify the element blocks on either side of the * side set. */ switch (bc_ptr->BC_Name) { /* * For these boundary conditions, the element block ID numbers * are in the firest two integer slots */ case POROUS_PRESSURE_BC: case DARCY_CONTINUOUS_BC: case Y_DISCONTINUOUS_BC: case POROUS_GAS_BC: case VP_EQUIL_BC: case VN_POROUS_BC: case FLUID_SOLID_BC: case SOLID_FLUID_BC: case NO_SLIP_BC: case FLUID_SOLID_CONTACT_BC: case SOLID_FLUID_CONTACT_BC: case T_CONTACT_RESIS_BC: case T_CONTACT_RESIS_2_BC: case LIGHTP_JUMP_BC: case LIGHTM_JUMP_BC: case LIGHTP_JUMP_2_BC: case LIGHTM_JUMP_2_BC: bc_ptr->BC_matrl_index_1 = map_mat_index(bc_ptr->BC_Data_Int[0]); bc_ptr->BC_matrl_index_2 = map_mat_index(bc_ptr->BC_Data_Int[1]); break; /* * For this boundary condition the element block numbers * are in the second and third integer slots */ case VL_EQUIL_BC: case YFLUX_DISC_RXN_BC: case DISCONTINUOUS_VELO_BC: bc_ptr->BC_matrl_index_1 = map_mat_index(bc_ptr->BC_Data_Int[1]); bc_ptr->BC_matrl_index_2 = map_mat_index(bc_ptr->BC_Data_Int[2]); break; } /* * Initialize quantities */ for (i = 0; i < 4 * upd->Num_Mat; i++) bin_matrl[i] = 0; for (i = 0; i < exo->num_nodes; i++) node_flag_1ss[i] = 0; max_node_matrl = min_node_matrl = -1; min_matrl = 4000000; max_matrl = -1; node_matrl_1 = node_matrl_2 = node_matrl_3 = node_matrl_4 = -1; /* * Determine how many materials each boundary condition needs * based on the type of the boundary condition */ i_apply_meth = BC_Types[ibc].desc->i_apply; if (i_apply_meth == CROSS_PHASE_DISCONTINUOUS || i_apply_meth == CROSS_PHASE) { num_matrl_needed = 2; } else if (i_apply_meth == SINGLE_PHASE) { num_matrl_needed = 1; } /* * Loop over the nodes in the side set looking up what * materials are located at each node * -> this will work for side sets. Need to do node sets * as well. */ if (!strcmp(bc_ptr->Set_Type, "SS")) { for (ss_index = 0; ss_index < exo->num_side_sets; ss_index++) { /* * This logic works for one side set specifications. For * two side set specifications (EDGES), we will have to go * with a calculation of the union of side sets. */ if (bc_ptr->BC_ID == exo->ss_id[ss_index]) { found = TRUE; for (side_index = 0; side_index < exo->ss_num_sides[ss_index]; side_index++) { /* * Locate the element number, find the material index, * then bin the result. */ ielem = exo->ss_elem_list[exo->ss_elem_index[ss_index]+side_index]; mat_index = find_mat_number(ielem, exo); bin_matrl_elem[mat_index]++; for (k = exo->ss_node_side_index[ss_index][side_index]; k < exo->ss_node_side_index[ss_index][side_index+1]; k++) { node_num = exo->ss_node_list[ss_index][k]; if (!node_flag_1ss[node_num]) { node_flag_1ss[node_num] = 1; node_ptr = Nodes[node_num]; matrlLP = &(node_ptr->Mat_List); /* * Bin the materials at this node for later usage. */ for (i = 0; i < matrlLP->Length; i++) { #ifdef DEBUG_IGNORE_ELEMENT_BLOCK_CAPABILITY if (matrlLP->List[i] < 0) { fprintf(stderr,"Material list contains negative number\n"); EH(-1,"logic error in ignoring an element block"); } #endif bin_matrl[matrlLP->List[i]]++; } /* * Find the max and min number of materials for a * node in this side set */ if (matrlLP->Length > max_matrl) { max_matrl = matrlLP->Length; max_node_matrl = node_num; } if (matrlLP->Length < min_matrl) { min_matrl = matrlLP->Length; min_node_matrl = node_num; } /* * Find representative nodes with specific * numbers of materials */ if (matrlLP->Length == 1) node_matrl_1 = node_num; if (matrlLP->Length == 2) node_matrl_2 = node_num; if (matrlLP->Length == 3) node_matrl_3 = node_num; if (matrlLP->Length == 4) node_matrl_4 = node_num; } } } } } /* End of side set loop */ } /* if SS */ /* * Node Sets */ if (!strcmp(bc_ptr->Set_Type, "NS")) { for (ss_index = 0; ss_index < exo->num_node_sets; ss_index++) { /* * This logic works for one side set specifications. For * two side set specifications (EDGES), we will have to go * with a calculation of the union of side sets. */ if (bc_ptr->BC_ID == exo->ns_id[ss_index]) { found = TRUE; /* * Loop over the number of nodes */ for (k = 0; k < exo->ns_num_nodes[ss_index]; k++) { node_num = exo->ns_node_list[exo->ns_node_index[ss_index]+k]; if (!node_flag_1ss[node_num]) { node_flag_1ss[node_num] = 1; node_ptr = Nodes[node_num]; matrlLP = &(node_ptr->Mat_List); /* * Bin the materials at this node for later usage. */ for (i = 0; i < matrlLP->Length; i++) { bin_matrl[matrlLP->List[i]]++; } /* * Find the max and min number of materials for a * node in this side set */ if (matrlLP->Length > max_matrl) { max_matrl = matrlLP->Length; max_node_matrl = node_num; } if (matrlLP->Length < min_matrl) { min_matrl = matrlLP->Length; min_node_matrl = node_num; } /* * Find representative nodes with specific * numbers of materials */ if (matrlLP->Length == 1) node_matrl_1 = node_num; if (matrlLP->Length == 2) node_matrl_2 = node_num; if (matrlLP->Length == 3) node_matrl_3 = node_num; if (matrlLP->Length == 4) node_matrl_4 = node_num; } } } } /* End of side set loop */ } /* if NS */ /* * Ok, we have obtained statistics on the side and node sets * let's make a decision */ if (found) { matrl_first = find_next_max(bin_matrl, ind_matrl, upd->Num_Mat); success = assign_matrl_2(bc_ptr, matrl_first); if (success < 0) { printf("%s P_%d: problem in assigning first matrl index in ibc %d, %d:\n", yo, ProcID, ibc, matrl_first); bc_matrl_index_print(bc_ptr, bin_matrl, bin_matrl_elem, min_node_matrl, max_node_matrl, node_matrl_1, node_matrl_2, node_matrl_3, node_matrl_4, ibc); } matrl_first = find_next_max(bin_matrl, ind_matrl, upd->Num_Mat); if (matrl_first >= 0) { success = assign_matrl_2(bc_ptr, matrl_first); if (success < 0) { printf("%s P_%d: problem in assigning second matrl index in ibc %d, %d:\n", yo, ProcID, ibc, matrl_first); bc_matrl_index_print(bc_ptr, bin_matrl, bin_matrl_elem, min_node_matrl, max_node_matrl, node_matrl_1, node_matrl_2, node_matrl_3, node_matrl_4, ibc); } } else { if (num_matrl_needed > 1) { printf("%s P_%d: problem in finding a needed second matrl index:\n", yo, ProcID); EH(-1,"bc_matrl_index ERROR"); } } } /* * For debug purposes, print out everything that we have found * out and decided about this bc on all of the processors. */ #ifdef DEBUG_HKM print_sync_start(FALSE); bc_matrl_index_print(bc_ptr, bin_matrl, bin_matrl_elem, min_node_matrl, max_node_matrl, node_matrl_1, node_matrl_2, node_matrl_3, node_matrl_4, ibc); print_sync_end(FALSE); #endif /* * MP Fix: We may not get the same results on all processors * In this case, just take the processor with the most * nodes in this bc and with a valid result, and use * that. Broadcast that result to all nodes. Cross your * fingers. */ node_count = 0; for (i = 0; i < exo->num_nodes; i++) { node_count += node_flag_1ss[i]; } #ifdef PARALLEL k = ProcWithMaxInt(node_count, &i); MPI_Bcast(&(bc_ptr->BC_matrl_index_1), 1, MPI_INT, k, MPI_COMM_WORLD); MPI_Bcast(&(bc_ptr->BC_matrl_index_2), 1, MPI_INT, k, MPI_COMM_WORLD); MPI_Bcast(&(bc_ptr->BC_matrl_index_3), 1, MPI_INT, k, MPI_COMM_WORLD); MPI_Bcast(&(bc_ptr->BC_matrl_index_4), 1, MPI_INT, k, MPI_COMM_WORLD); #ifdef DEBUG_HKM print_sync_start(FALSE); if ( !ProcID ) { printf("Final matrl_index's for ibc = %d:\n", ibc); printf("\tBC_matrl_index_1 = %d\n", bc_ptr->BC_matrl_index_1); printf("\tBC_matrl_index_2 = %d\n", bc_ptr->BC_matrl_index_2); printf("\tBC_matrl_index_3 = %d\n", bc_ptr->BC_matrl_index_3); printf("\tBC_matrl_index_4 = %d\n", bc_ptr->BC_matrl_index_4); fflush(stdout); } print_sync_end(FALSE); #endif #endif } safer_free((void **) &bin_matrl); safer_free((void **) &node_flag_1ss); }
int ns_data_print(pp_Data * p, double x[], const Exo_DB * exo, const double time_value, const double time_step_size) { const int quantity = p->data_type; int mat_num = p->mat_num; const int elemBlock_id = p->elem_blk_id; const int node_set_id = p->ns_id; const int species_id = p->species_number; const char * filenm = p->data_filenm; const char * qtity_str = p->data_type_name; const char * format_flag = p->format_flag; int * first_time = &(p->first_time); static int err=0; int num_nodes_on_side; int ebIndex_first = -1; int local_side[2]; int side_nodes[3]; /* Assume quad has no more than 3 per side. */ int elem_list[4], elem_ct=0, face, ielem, node2; int local_node[4]; int node = -1; int idx, idy, idz, id_var; int iprint; int nsp; /* node set pointer for this node set */ dbl x_pos, y_pos, z_pos; int j, wspec; int doPressure = 0; #ifdef PARALLEL double some_time=0.0; #endif double abscissa=0; double ordinate=0; double n1[3], n2[3]; double xi[3]; /* * Find an element block that has the desired material id. */ if (elemBlock_id != -1) { for (j = 0; j < exo->num_elem_blocks; j++) { if (elemBlock_id == exo->eb_id[j]) { ebIndex_first = j; break; } } if (ebIndex_first == -1) { sprintf(err_msg, "Can't find an element block with the elem Block id %d\n", elemBlock_id); if (Num_Proc == 1) { EH(-1, err_msg); } } mat_num = Matilda[ebIndex_first]; p->mat_num = mat_num; pd = pd_glob[mat_num]; } else { mat_num = -1; p->mat_num = -1; pd = pd_glob[0]; } nsp = match_nsid(node_set_id); if( nsp != -1 ) { node = Proc_NS_List[Proc_NS_Pointers[nsp]]; } else { sprintf(err_msg, "Node set ID %d not found.", node_set_id); if( Num_Proc == 1 ) EH(-1,err_msg); } /* first right time stamp or run stamp to separate the sets */ print_sync_start(FALSE); if (*first_time) { if ( format_flag[0] != '\0' ) { if (ProcID == 0) { uf = fopen(filenm,"a"); if (uf != NULL) { fprintf(uf,"# %s %s @ nsid %d node (%d) \n", format_flag, qtity_str, node_set_id, node ); *first_time = FALSE; fclose(uf); } } } } if (format_flag[0] == '\0') { if (ProcID == 0) { if ((uf = fopen(filenm,"a")) != NULL) { fprintf(uf,"Time/iteration = %e \n", time_value); fprintf(uf," %s Node_Set %d Species %d\n", qtity_str,node_set_id,species_id); fflush(uf); fclose(uf); } } } if (nsp != -1 ) { for (j = 0; j < Proc_NS_Count[nsp]; j++) { node = Proc_NS_List[Proc_NS_Pointers[nsp]+j]; if (node < num_internal_dofs + num_boundary_dofs ) { idx = Index_Solution(node, MESH_DISPLACEMENT1, 0, 0, -1); if (idx == -1) { x_pos = Coor[0][node]; WH(idx, "Mesh variable not found. May get undeformed coords."); } else { x_pos = Coor[0][node] + x[idx]; } idy = Index_Solution(node, MESH_DISPLACEMENT2, 0, 0, -1); if (idy == -1) { y_pos = Coor[1][node]; } else { y_pos = Coor[1][node] + x[idy]; } z_pos = 0.; if(pd->Num_Dim == 3) { idz = Index_Solution(node, MESH_DISPLACEMENT3, 0, 0, -1); if (idz == -1) { z_pos = Coor[2][node]; } else{ z_pos = Coor[2][node] + x[idz]; } } if (quantity == MASS_FRACTION) { id_var = Index_Solution(node, quantity, species_id, 0, mat_num); } else if (quantity < 0) { id_var = -1; } else { id_var = Index_Solution(node, quantity, 0, 0, mat_num); } /* * In the easy case, the variable can be found somewhere in the * big vector of unknowns. But sometimes we want a derived quantity * that requires a little more work than an array reference. * * For now, save the good result if we have it. */ if ( id_var != -1 ) { ordinate = x[id_var]; iprint = 1; } else { /* * If we have an element based interpolation, let's calculate the interpolated value */ if (quantity == PRESSURE) { if ((pd->i[PRESSURE] == I_P1) || ( (pd->i[PRESSURE] > I_PQ1) && (pd->i[PRESSURE] < I_Q2_HVG) )) { doPressure = 1; } } iprint = 0; } /* * If the quantity is "theta", an interior angle that only * makes sense at a point, in 2D, we'll need to compute it. */ if ( strncasecmp(qtity_str, "theta", 5 ) == 0 || doPressure) { /* * Look for the two sides connected to this node...? * * Premise: * 1. The node appears in only one element(removed-RBS,6/14/06) * 2. Exactly two sides emanate from the node. * 3. Quadrilateral. * * Apologies to people who wish to relax premise 1. I know * there are some obtuse angles out there that benefit from * having more than one element at a vertex. With care, this * procedure could be extended to cover that case as well. */ if ( ! exo->node_elem_conn_exists ) { EH(-1, "Cannot compute angle without node_elem_conn."); } elem_list[0] = exo->node_elem_list[exo->node_elem_pntr[node]]; /* * Find out where this node appears in the elements local * node ordering scheme... */ local_node[0] = in_list(node, exo->elem_node_pntr[elem_list[0]], exo->elem_node_pntr[elem_list[0]+1], exo->elem_node_list); EH(local_node[0], "Can not find node in elem node connectivity!?! "); local_node[0] -= exo->elem_node_pntr[elem_list[0]]; /* check for neighbors*/ if( mat_num == find_mat_number(elem_list[0], exo)) {elem_ct = 1;} else {WH(-1,"block id doesn't match first element");} for (face=0 ; face<ei->num_sides ; face++) { ielem = exo->elem_elem_list[exo->elem_elem_pntr[elem_list[0]]+face]; if (ielem != -1) { node2 = in_list(node, exo->elem_node_pntr[ielem], exo->elem_node_pntr[ielem+1], exo->elem_node_list); if (node2 != -1 && (mat_num == find_mat_number(ielem, exo))) { elem_list[elem_ct] = ielem; local_node[elem_ct] = node2; local_node[elem_ct] -= exo->elem_node_pntr[ielem]; elem_ct++; } } } /* * Note that indeces are zero based! */ ordinate = 0.0; for (ielem = 0 ; ielem < elem_ct ; ielem++) { if ( local_node[ielem] < 0 || local_node[ielem] > 3 ) { if (strncasecmp(qtity_str, "theta", 5 ) == 0) { EH(-1, "Node out of bounds."); } } /* * Now, determine the local name of the sides adjacent to this * node...this works for the exo patran convention for quads... * * Again, local_node and local_side are zero based... */ local_side[0] = (local_node[ielem]+3)%4; local_side[1] = local_node[ielem]; /* * With the side names, we can find the normal vector. * Again, assume the sides live on the same element. */ load_ei(elem_list[ielem], exo, 0); /* * We abuse the argument list under the conditions that * we're going to do read-only operations and that * we're not interested in old time steps, time derivatives * etc. */ if (x == x_static) /* be the least disruptive possible */ { err = load_elem_dofptr(elem_list[ielem], exo, x_static, x_old_static, xdot_static, xdot_old_static, x_static, 1); } else { err = load_elem_dofptr(elem_list[ielem], exo, x, x, x, x, x, 1); } /* * What are the local coordinates of the nodes in a quadrilateral? */ find_nodal_stu(local_node[ielem], ei->ielem_type, xi, xi+1, xi+2); err = load_basis_functions(xi, bfd); EH( err, "problem from load_basis_functions"); err = beer_belly(); EH( err, "beer_belly"); err = load_fv(); EH( err, "load_fv"); err = load_bf_grad(); EH( err, "load_bf_grad"); err = load_bf_mesh_derivs(); EH(err, "load_bf_mesh_derivs"); if (doPressure) { ordinate = fv->P; iprint = 1; } else { /* First, one side... */ get_side_info(ei->ielem_type, local_side[0]+1, &num_nodes_on_side, side_nodes); surface_determinant_and_normal(elem_list[ielem], exo->elem_node_pntr[elem_list[ielem]], ei->num_local_nodes, ei->ielem_dim-1, local_side[0]+1, num_nodes_on_side, side_nodes); n1[0] = fv->snormal[0]; n1[1] = fv->snormal[1]; /* Second, the adjacent side of the quad... */ get_side_info(ei->ielem_type, local_side[1]+1, &num_nodes_on_side, side_nodes); surface_determinant_and_normal(elem_list[ielem], exo->elem_node_pntr[elem_list[ielem]], ei->num_local_nodes, ei->ielem_dim-1, local_side[1]+1, num_nodes_on_side, side_nodes); n2[0] = fv->snormal[0]; n2[1] = fv->snormal[1]; /* cos (theta) = n1.n2 / ||n1|| ||n2|| */ ordinate += 180. - (180./M_PI)*acos((n1[0]*n2[0] + n1[1]*n2[1])/ (sqrt(n1[0]*n1[0]+n1[1]*n1[1])* sqrt(n2[0]*n2[0]+n2[1]*n2[1]))); } iprint = 1; } /*ielem loop */ } else if ( strncasecmp(qtity_str, "timestepsize", 12 ) == 0 ) { ordinate = time_step_size; iprint = 1; } else if ( strncasecmp(qtity_str, "cputime", 7 ) == 0 ) { ordinate = ut(); iprint = 1; } else if ( strncasecmp(qtity_str, "wallclocktime", 13 ) == 0 ) { /* Get these from extern via main...*/ #ifdef PARALLEL some_time = MPI_Wtime(); ordinate = some_time - time_goma_started; #endif #ifndef PARALLEL time_t now=0; (void)time(&now); ordinate = (double)(now) - time_goma_started; #endif iprint = 1; } else if ( strncasecmp(qtity_str, "speed", 5 ) == 0 ) { id_var = Index_Solution(node, VELOCITY1, 0, 0, mat_num); ordinate = SQUARE(x[id_var]); id_var = Index_Solution(node, VELOCITY2, 0, 0, mat_num); ordinate += SQUARE(x[id_var]); id_var = Index_Solution(node, VELOCITY3, 0, 0, mat_num); ordinate += SQUARE(x[id_var]); ordinate = sqrt(ordinate); iprint = 1; } else if ( strncasecmp(qtity_str, "ac_pres", 7 ) == 0 ) { id_var = Index_Solution(node, ACOUS_PREAL, 0, 0, mat_num); ordinate = SQUARE(x[id_var]); id_var = Index_Solution(node, ACOUS_PIMAG, 0, 0, mat_num); ordinate += SQUARE(x[id_var]); ordinate = sqrt(ordinate); iprint = 1; } else if ( strncasecmp(qtity_str, "light_comp", 10 ) == 0 ) { id_var = Index_Solution(node, LIGHT_INTP, 0, 0, mat_num); ordinate = x[id_var]; id_var = Index_Solution(node, LIGHT_INTM, 0, 0, mat_num); ordinate += x[id_var]; iprint = 1; } else if ( strncasecmp(qtity_str, "nonvolatile", 11 ) == 0 ) { ordinate = 1.0; for(wspec = 0 ; wspec < pd->Num_Species_Eqn ; wspec++) { id_var = Index_Solution(node, MASS_FRACTION, wspec, 0, mat_num); ordinate -= x[id_var]*mp_glob[mat_num]->molar_volume[wspec]; } iprint = 1; } else { WH(id_var, "Requested print variable is not defined at all nodes. May get 0."); if(id_var == -1) iprint = 0; } if ((uf=fopen(filenm,"a")) != NULL) { if ( format_flag[0] == '\0' ) { if (iprint) { fprintf(uf," %e %e %e %e \n", x_pos, y_pos, z_pos, ordinate); } } else { if ( strncasecmp(format_flag, "t", 1) == 0 ) { abscissa = time_value; } else if ( strncasecmp(format_flag, "x", 1) == 0 ) { abscissa = x_pos; } else if ( strncasecmp(format_flag, "y", 1) == 0 ) { abscissa = y_pos; } else if ( strncasecmp(format_flag, "z", 1) == 0 ) { abscissa = z_pos; } else { abscissa = 0; } if (iprint) { fprintf(uf, "%.16g\t%.16g\n", abscissa, ordinate); } } fclose(uf); } } } } print_sync_end(FALSE); return(1); } /* END of routine ns_data_print */