// -*- C++ -*-
// $RCSfile: ppm2oof2.C,v $
// $Revision: 1.5 $
// $Author: langer $
// $Date: 2005/02/17 19:11:31 $
/* This software was produced by NIST, an agency of the U.S. government,
* and by statute is not subject to copyright in the United States.
* Recipients of this software assume all responsibilities associated
* with its operation, modification and maintenance. However, to
* facilitate maintenance we ask that before distributing modifed
* versions of this software, you first contact the authors at
* oof_manager@ctcms.nist.gov.
*/
// Functions for exporting OOF1 data to OOF2.
#include "adaptmesh.h"
#include "amtriangle.h"
#include "filename.h"
#include "material.h"
#ifdef THERMAL
#include "materialT.h"
#endif // THERMAL
#include "output.h"
#include "version.h"
static CharString newMaterialName() {
static int count = 0;
return "_material_" + to_charstring(++count);
}
void AdaptiveMesh::find_material_groups(Vec<MeshGroup*> &mgrps,
const Vec<PixelGroup*> &pgrps) const
{
for(AMIterator i(this, AMI_ALL); !i.end(); ++i) {
AMTriangle *tri = (*this)[i];
Material *mat = tri->resolve_material();
// Is this material already in a group?
bool foundit = false;
for(int j=0; j<mgrps.capacity() && !foundit; j++) {
if(*(*mgrps[j])[0]->resolve_material() == *mat) {
mgrps[j]->append(tri);
foundit = true;
}
}
if(!foundit) { // Create a new group
// Find the name of the pixel group for this Material.
CharString name;
for(int j=0; j<pgrps.capacity() && !name; j++) {
Material *othermat = goof->material[(*pgrps[j])[0]];
if(!othermat) othermat = defaultmaterial;
if(*othermat == *mat)
name = pgrps[j]->query_name();
}
MeshGroup *newgroup = new MeshGroup(name);
mgrps.grow(1, newgroup);
newgroup->append(tri);
}
}
}
void Goof::find_material_groups(Vec<PixelGroup*> &pgrps) {
pgrps.resize(0);
Cell_coordinate pixel;
ArrayIterator iter(material);
while(iter(pixel)) {
bool foundit = false;
for(int i=0; i<pgrps.capacity() && !foundit; i++) {
Material *mat = material[pixel];
if(!mat)
mat = defaultmaterial;
Cell_coordinate &otherpxl = (*pgrps[i])[0];
Material *othermat = material[otherpxl];
if(!othermat)
othermat = defaultmaterial;
if(*mat == *othermat) {
pgrps[i]->append(pixel);
foundit = true;
}
}
if(!foundit) {
PixelGroup *grp = add_group(newMaterialName());
pgrps.grow(1, grp);
grp->append(pixel);
}
}
}
static void cleanPgrps(Vec<PixelGroup*> *pgrps) {
for(int i=0; i<pgrps->capacity(); i++) {
current_goof->remove_group((*pgrps)[i]->query_name());
// delete (*pgrps)[i];
}
}
// ----------------
bool Goof::check_plane_strain(const Vec<PixelGroup*> &pgrps, bool &ok) const {
PixelGroup &pgrp = *pgrps[0];
Material *mat = material[pgrp[0]];
if(!mat)
mat = defaultmaterial;
bool plane_strain = mat->query_planestrain();
for(int i=1; i<pgrps.capacity(); i++) {
PixelGroup &pgrp = *pgrps[i];
const Material *mat = material[pgrp[0]];
if(!mat)
mat = defaultmaterial;
if(mat->query_planestrain() != plane_strain) {
ok = false;
return plane_strain;
}
}
ok = true;
return plane_strain;
}
#ifdef THERMAL
bool Goof::check_Tplanarity(const Vec<PixelGroup*> &pgrps, bool &ok) const {
bool started = false;
bool Tplanarity;
for(int i=0; i<pgrps.capacity(); i++) {
PixelGroup &pgrp = *pgrps[i];
const Material *mat = material[pgrp[0]];
if(!mat)
mat = defaultmaterial;
const MaterialT *matT = dynamic_cast<const MaterialT*>(mat);
if(matT) {
if(!started) {
Tplanarity = matT->query_Tplanarity();
started = true;
}
else {
if(matT->query_Tplanarity() != Tplanarity) {
ok = false;
return Tplanarity;
}
}
}
}
ok = true;
return Tplanarity;
}
#endif // THERMAL
// ----------------
void Goof::print_materials(ostream &os, const Vec<PixelGroup*> &pgrps) const {
os << endl;
os << "## The materials defined in this data file come from the following"
<< endl;
os << "## OOF1 element definitions. The data file also contains an element"
<< endl;
os << "## group with the same name as the material." << endl;
for(int i=0; i<pgrps.capacity(); i++) {
PixelGroup &grp = *pgrps[i];
Material *mat = material[grp[0]];
if(!mat)
mat = defaultmaterial;
os << "## " << grp.query_name() << ": " << mat->parameters << endl;
}
os << endl;
for(int i=0; i<pgrps.capacity(); i++) {
PixelGroup &grp = *pgrps[i];
Material *mat = material[grp[0]];
if(!mat)
mat = defaultmaterial;
mat->write_oof2(os, grp.query_name());
}
}
// ----------------
void Goof::print_pixelgroups(ostream &os, const CharString &msName) const {
for(int i=0; i<grouplist.capacity(); i++) {
os << "OOF.LoadData.Microstructure.PixelGroup(microstructure='"
<< msName
<< "', group='" << grouplist[i]->query_name()
<< "', meshable=1)" << endl;
}
}
// ------------
void Goof::print_images(ostream &os, const CharString &msName) const {
for(int p=0; p<gallery.capacity(); p++) {
const NamedImage &image = *gallery[p];
std::vector<unsigned short> pxls;
for(int j=0; j<image.query_height(); j++) {
for(int i=0; i<image.query_width(); i++) {
const Color &color = image[Cell_coordinate(i,j)];
pxls.push_back((unsigned short)255*color.query_red());
pxls.push_back((unsigned short)255*color.query_green());
pxls.push_back((unsigned short)255*color.query_blue());
}
}
os << "OOF.LoadData.Image.New(name='" << image.name()
<< "', microstructure='" << msName
<< "', pixels=RGBData8(rgbvalues=[" << pxls[0];
for(int i=1; i<pxls.size(); i++)
os << ", " << pxls[i];
os << "]))" << endl;
}
}
// ------------
void Goof::print_categories(ostream &os , const CharString &msName,
const Vec<PixelGroup*> &pgrps)
{
categorize_pixels();
int w = query_width();
int h = query_height();
os << "OOF.LoadData.Microstructure.Categories(microstructure='" << msName
<< "', categories=[";
for(int j=0; j<h; j++) {
os << "[";
for(int i=0; i<w; i++) {
os << pixelcategory[Cell_coordinate(i,j)];
if(i < w-1)
os << ",";
}
os << "]";
if(j < h-1)
os << ",";
}
os << "])" << endl;
// Assign materials and pixel groups to catgories.
for(int cat=0; cat<Ncategories; cat++) {
const Cell_coordinate &pxl = categorical_pixel(cat);
Material *mat = material[pxl];
if(!mat)
mat = defaultmaterial;
// Find which material group corresponds to this material. This
// is bass-ackward, but Material instances don't have names in
// ppm2oof, and we need to know the name that was assigned to the
// Material in Goof::find_material_groups.
bool ok = false;
for(int i=0; i<pgrps.capacity() && !ok; i++) {
PixelGroup &grp = *pgrps[i];
Material *grpmat = material[grp[0]];
if(!grpmat)
grpmat = defaultmaterial;
if(*grpmat == *mat) {
os << "OOF.LoadData.Microstructure.DefineCategory.Material("
<< "microstructure='" << msName
<< "', category=" << cat
<< ", material='" << grp.query_name() << "')" << endl;
}
}
LinkList<PixelGroup*> pglist = pixelgrouplist[pxl];
if(pglist.size() > 0) {
os << "OOF.LoadData.Microstructure.DefineCategory.PixelGroups("
<< "microstructure='" << msName
<< "', category=" << cat
<< ", groups=[";
for(LinkListIterator<PixelGroup*> i=pglist.begin(); !i.end(); ++i)
os << "'" << pglist[i]->query_name() << "',";
os << "])" << endl;
}
}
os << "OOF.LoadData.Microstructure.EndCategories(microstructure='" << msName
<< "')" << endl;
}
// ------------
bool Goof::write_oof2(ostream &os, const CharString &msName,
Vec<PixelGroup*> *pgrps)
{
// Look for materials in the Goof, and create a PixelGroup for each
// Material.
if(!prepare_output()) return false;
bool ownpgrps = false;
if(!pgrps) {
pgrps = new Vec<PixelGroup*>;
ownpgrps = true;
}
find_material_groups(*pgrps);
bool ok;
bool plane_strain = check_plane_strain(*pgrps, ok);
if(!ok) {
garcon()->msout << ms_error <<
"Materials must all be plane stress or all be plane strain!"
<< endl << ms_normal;
return false;
}
#ifdef THERMAL
bool Tplanarity = check_Tplanarity(*pgrps, ok);
if(!ok) {
garcon()->msout << ms_error <<
"Materials must all have T_planarity=true or all have T_planarity=false!"
<< endl << ms_normal;
return false;
}
#endif // THERMAL
// Header
os << "# OOF version 2.0" << endl;
os << "# OOF2 data file created by PPM2OOF" << ppm2oofversion() << endl;
os << "OOF.LoadData.FileVersion(number=1.0, format='script')" << endl;
print_materials(os, *pgrps);
// Create a Microstructure
double physical_height =
physical_width*query_height()/query_width();
os << "OOF.LoadData.Microstructure.New(name='" << msName
<< "', size=Point(" << physical_width << ", " << physical_height
<< "), isize=iPoint(" << query_width() << ", " << query_height() << "))"
<< endl;
// Store Images
print_images(os, msName);
// Create pixel groups
print_pixelgroups(os, msName);
// Store pixel categories
print_categories(os, msName, *pgrps);
if(ownpgrps) {
cleanPgrps(pgrps);
delete pgrps;
}
return true;
}
// ------------
void AdaptiveMesh::print_nodes(ostream &os, const CharString &skeletonName)
const
{
double dx = physical_width/goof->query_width();
os << "OOF.LoadData.Skeleton.Nodes(skeleton='" << skeletonName
<< "', points=[";
for(int i=0; i<nodes.capacity(); i++) {
MeshCoord where = dx*nodes[i]->coord();
os << "(" << where.x << ", " << where.y << "),";
}
os << "])" << endl;
}
void AdaptiveMesh::print_elements(ostream &os, const CharString &skeletonName)
const
{
set_triangle_indices();
os << "OOF.LoadData.Skeleton.Elements(skeleton='" << skeletonName
<< "', nodes=[";
for(AMIterator iter(this, AMI_ALL); !iter.end(); ++iter) {
(*this)[iter]->writeoof2(os);
os << ",";
}
os << "])" << endl;
}
void AMTriangle::writeoof2(ostream &os) const {
os << "(" << node[0]->index << "," << node[1]->index << ","
<< node[2]->index << ")";
}
static void print_nodegroup(ostream &os, const CharString &skeletonName,
const CharString &grpname,
const Vec<int> &members)
{
os << "OOF.LoadData.Skeleton.NodeGroup(skeleton='" << skeletonName
<< "', name='" << grpname
<< "', nodes=[";
for(int i=0; i<members.capacity(); i++)
os << members[i] << ",";
os << "])" << endl;
}
void AdaptiveMesh::print_nodegroups(ostream &os, const CharString &skeletonName)
const
{
Vec<int> top;
Vec<int> btm;
Vec<int> lft;
Vec<int> rgt;
// The next four lists will have only one member each, but this is
// the easy way to code it and there's no significant performance
// penalty for doing it the sleazy way.
Vec<int> toplft;
Vec<int> btmlft;
Vec<int> toprgt;
Vec<int> btmrgt;
// find which nodes are on the edges
for(int i=0; i<nodes.capacity(); i++) {
if(nodes[i]->lft()) lft.grow(1, i);
if(nodes[i]->rgt()) rgt.grow(1, i);
if(nodes[i]->btm()) btm.grow(1, i);
if(nodes[i]->top()) top.grow(1, i);
if(nodes[i]->top() && nodes[i]->lft()) toplft.grow(1, i);
if(nodes[i]->top() && nodes[i]->rgt()) toprgt.grow(1, i);
if(nodes[i]->btm() && nodes[i]->lft()) btmlft.grow(1, i);
if(nodes[i]->btm() && nodes[i]->rgt()) btmrgt.grow(1, i);
}
print_nodegroup(os, skeletonName, "top", top);
print_nodegroup(os, skeletonName, "bottom", btm);
print_nodegroup(os, skeletonName, "left", lft);
print_nodegroup(os, skeletonName, "right", rgt);
print_nodegroup(os, skeletonName, "topleft", toplft);
print_nodegroup(os, skeletonName, "topright", toprgt);
print_nodegroup(os, skeletonName, "bottomleft", btmlft);
print_nodegroup(os, skeletonName, "bottomright", btmrgt);
}
void AdaptiveMesh::print_elementgroups(ostream &os,
const CharString &skeletonName,
const Vec<MeshGroup*> &groups)
const
{
for(int g=0; g<groups.capacity(); g++) {
const MeshGroup &group = *groups[g];
os << "OOF.LoadData.Skeleton.ElementGroup(skeleton='" << skeletonName
<< "', name='" << group.query_name()
<< "', elements=[";
for(int i=0; i<group.size(); i++)
os << group[i]->index << ",";
os << "])" << endl;
}
}
static void make_boundaries(ostream &os, const CharString &skeletonName) {
// The top, bottom, right, and left boundaries are constructed as
// OOF2 point boundaries, rather than OOF2 edge boundaries, because
// that's the way to reproduce the OOF1 behavior.
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='top', constructor=PointFromNodes(group='top'))" << endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='left', constructor=PointFromNodes(group='left'))" << endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='bottom', constructor=PointFromNodes(group='bottom'))" << endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='right', constructor=PointFromNodes(group='right'))" << endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='bottomleft', constructor=PointFromNodes(group='bottomleft'))"
<< endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='bottomright', constructor=PointFromNodes(group='bottomright'))"
<< endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='topleft', constructor=PointFromNodes(group='topleft'))"
<< endl;
os << "OOF.Skeleton.Boundary.Construct(skeleton='" << skeletonName
<< "', name='topright', constructor=PointFromNodes(group='topright'))"
<< endl;
}
// ------------
void AdaptiveMesh::write_oof2(ostream &os, const CharString &msName) {
Vec<PixelGroup*> pgrps;
if(!goof->write_oof2(os, msName, &pgrps))
return;
// Catalog the distinct material types in the mesh. Create a
// MeshGroup for each Material. Use the pixel groups to name the
// mesh groups.
Vec<MeshGroup*> mgrps;
find_material_groups(mgrps, pgrps);
// Element groups are created automatically for each pixel group.
// Pixel groups have been created for each material, so there is
// already an element group for each material. BUT, depending on
// the way that pixel groups are inherited by the mesh, the existing
// element groups don't necessarily contain the correct elements
// (those elements sharing a material). SO, before printing the
// element groups, we must destroy the pixel groups for the
// materials.
cleanPgrps(&pgrps);
inherit_pixel_groups();
if(!prepare_output()) return;
// Create a Skeleton
CharString skeletonName = msName + ":skeleton";
os << "OOF.LoadData.Skeleton.New(name='skeleton', microstructure='"
<< msName << "')" << endl;
print_nodes(os, skeletonName);
print_elements(os, skeletonName);
print_nodegroups(os, skeletonName);
print_elementgroups(os, skeletonName, grouplist);
print_elementgroups(os, skeletonName, mgrps);
make_boundaries(os, skeletonName);
}
syntax highlighted by Code2HTML, v. 0.9.1