/* Copyright (C) 2003 by Sean David Fleming and Andrew Walker sean@ivec.org andrew.m.walker@anu.edu.au This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The GNU GPL can also be found at http://www.gnu.org */ #include #include #include #include #include #include #include "gdis.h" #include "file.h" #include "scan.h" #include "parse.h" #include "coords.h" #include "defect.h" #include "edit.h" #include "graph.h" #include "dialog.h" #include "model.h" #include "matrix.h" #include "geometry.h" #include "numeric.h" #include "space.h" #include "surface.h" #include "task.h" #include "zone.h" #include "interface.h" #include "shortcuts.h" extern struct sysenv_pak sysenv; /*************************/ /* check for 2-fold axes */ /*************************/ void defect_check_symmetry(struct model_pak *model) { gint i, n; for (i=1 ; isginfo.order ; i++) { n = matrix_is_z_rotation(*(model->sginfo.matrix+i)); if (n) { printf("matrix %d", i); P3MAT(" ", *(model->sginfo.matrix+i)); P3VEC("+", *(model->sginfo.offset+i)); printf(" : is a %d rotation axis\n", n); } } } /*****************************************/ /* acquire the elastic compliance matrix */ /*****************************************/ gint defect_compliance_get(gdouble *s, struct plane_pak *plane, struct model_pak *source) { gint i, j, tokens; gchar *inp, *out, *line, **buff; gchar *full_inp, *full_out; gpointer scan; struct model_pak *model; g_assert(source != NULL); /* I thought we could use the true cell stuff, but it's too messy */ /* given that the dislocation is based on distance from cylinder center */ printf("generating transformed cell.\n"); model = model_new(); source->surface.true_cell = TRUE; ARR3SET(model->surface.miller, plane->m); model->surface.region[0] = 1; model->surface.region[1] = 0; model->surface.shift = 0.0; generate_surface(source, model); /* setup "surface" for GULP calc */ gulp_data_copy(source, model); /* this can have crap in it that stuffs up the GULP run */ /* gulp_extra_copy(source, model); */ /* run the required GULP job */ model->gulp.prop = TRUE; model->gulp.run = E_OPTIMIZE; /* this tells GULP to output lattice vectors */ model->construct_pbc = TRUE; model->periodic = 3; /* get a temporary name */ inp = gun("gin"); out = gun("got"); full_inp = g_build_filename(sysenv.cwd, inp, NULL); full_out = g_build_filename(sysenv.cwd, out, NULL); g_free(inp); g_free(out); printf("acquiring elastic compliance matrix...\n"); write_gulp(full_inp, model); if (exec_gulp(full_inp, full_out)) return(1); /* process the output */ scan = scan_new(full_out); if (!scan) return(2); while (!scan_complete(scan)) { line = scan_get_line(scan); if (line) if (g_strncasecmp(line, " Elastic Compliance Matrix:", 28) == 0) { for (i=4 ; i-- ; ) scan_get_line(scan); for (i=0 ; i<6 ; i++) { buff = scan_get_tokens(scan, &tokens); if (tokens > 6) { for (j=0 ; j<6 ; j++) s[6*i+j] = str_to_float(*(buff+j+1)); } else printf("Error parsing constants.\n"); g_strfreev(buff); } } } scan_free(scan); unlink(full_inp); unlink(full_out); g_free(full_inp); g_free(full_out); model_free(model); sysenv.mal = g_slist_remove(sysenv.mal, model); g_free(model); return(0); } /********************************************************/ /* create a cylinder (xy cross section) of given radius */ /********************************************************/ void defect_make_cylinder(gdouble *o, gdouble r1, gdouble r2, struct model_pak *model) { gint region; gdouble r, rsq, r1sq, d2, x[3]; GSList *mlist, *clist; struct mol_pak *mol; struct core_pak *core; struct shel_pak *shell; g_assert(model != NULL); r = r1+r2; rsq = r*r; r1sq = r1*r1; /* generate enough unit cells to satisfy input radius */ /* NB: round up the image number required */ model->image_limit[0] = (gint) (1 + r / model->pbc[0]); model->image_limit[1] = (gint) (1 + r / model->pbc[0]); model->image_limit[2] = (gint) (1 + r / model->pbc[1]); model->image_limit[3] = (gint) (1 + r / model->pbc[1]); model->image_limit[4] = 0.0; model->image_limit[5] = 1.0; space_make_images(CREATE, model); space_make_supercell(model); /* convert to cartesian block */ coords_make_cartesian(model); model->periodic = 0; model->fractional = FALSE; coords_compute(model); zone_init(model); /* if we cleave by atoms - prevent bonding anything, so each molecule is an atom */ /* NB: not sure why, but source's bonds are transferred to model */ if (model->surface.ignore_bonding) wipe_bonds(model); else connect_bonds(model); connect_molecules(model); /* offset by desired amount and clip */ /* TODO - if (!cleave) else by atom */ for (mlist=model->moles ; mlist ; mlist=g_slist_next(mlist)) { mol = mlist->data; /* transform the centroid */ ARR3SET(x, mol->centroid); /* FIXME - o is fractional - x is not? */ x[0] -= o[0]; x[1] -= o[1]; d2 = x[0]*x[0] + x[1]*x[1]; if (d2 < rsq) { if (d2 < r1sq) region = 0; else region = 1; for (clist=mol->cores ; clist ; clist=g_slist_next(clist)) { core = clist->data; core->x[0] -= o[0]; core->x[1] -= o[1]; core->region = region; if (core->shell) { shell = core->shell; shell->x[0] -= o[0]; shell->x[1] -= o[1]; shell->region = region; } } } else { for (clist=mol->cores ; clist ; clist=g_slist_next(clist)) { core = clist->data; delete_core(core); } } } } /******************************/ /* displace the supplied core */ /******************************/ gdouble defect_anisotropic_1(gdouble *x, gdouble r44, gdouble r55, gdouble *b) { gdouble angle; angle = angle_x_compute(x[0], x[1]); /* -ve ??? */ angle *= sqrt(fabs(r44)/fabs(r55)); return(0.5 * VEC3MAG(b) * angle / G_PI); } /************************************************/ /* do coordinate offsets for a scew dislocation */ /************************************************/ void defect_screw_dislocate(gdouble *s, gdouble *v, struct model_pak *model) { gdouble dz, r44, r55, x[3]; GSList *clist, *mlist; struct mol_pak *mol; struct core_pak *core; struct shel_pak *shell; g_assert(model != NULL); /* r44 = s44 - (s34 s34 / s33) */ r44 = s[21] - ((s[15]*s[15])/s[14]); /* r55 = s55 - (s35 s35 / s33) */ r55 = s[28] - ((s[16]*s[16])/s[14]); printf("\nReduced elastic compliances: S44 = %f, S55 = %f\n", r44, r55); if (r44 == r55) printf("Isotropic case...\n"); if (fabs(r44) < FRACTION_TOLERANCE || fabs(r55) < FRACTION_TOLERANCE) { printf("Bad compliance matrix.\n"); return; } for (mlist=model->moles ; mlist ; mlist=g_slist_next(mlist)) { mol = mlist->data; ARR3SET(x, mol->centroid); dz = defect_anisotropic_1(x, r44, r55, v); for (clist=mol->cores ; clist ; clist=g_slist_next(clist)) { core = clist->data; core->x[2] += dz; if (core->shell) { shell = core->shell; shell->x[2] += dz; } } } } /*********************************************************************/ /* attempt to find an int which will multiply to make a float an int */ /*********************************************************************/ /* TODO - put in numeric */ gint numeric_make_whole(gdouble x) { gint i; gdouble frac, f; frac = fabs(x - nearest_int(x)); if (frac > FRACTION_TOLERANCE) { /* crude hack - look for common extensions */ for (i=2 ; i<9 ; i++) { f = 1.0 / (gdouble) i; if (fabs(frac-f) < FRACTION_TOLERANCE) return(i); } return(0); } else return(nearest_int(x)); } /********************/ /* build the defect */ /********************/ #define DEBUG_DEFECT_NEW 1 void defect_new(struct defect_pak *defect, struct model_pak *source) { gint height, gcd, mult1, mult2; gdouble r, len; gdouble o[2], v[3], b[3], m[9], s[36]; gdouble w[3], x[3], x1[3], x2[3], x3[3]; GSList *list; struct model_pak *model; struct plane_pak *plane; struct core_pak *core; struct shel_pak *shell; g_assert(defect != NULL); g_assert(source != NULL); /* check for 2-fold axes */ defect_check_symmetry(source); if (VEC3MAGSQ(defect->orient) < FRACTION_TOLERANCE) { gui_text_show(ERROR, "Please specify a non-zero dislocation vector.\n"); return; } /* setup the defect geometry */ ARR3SET(v, defect->orient); ARR3SET(b, defect->burgers); vecmat(source->latmat, v); vecmat(source->latmat, b); matrix_z_alignment(m, v); vecmat(m, v); vecmat(m, b); #if DEBUG_DEFECT_NEW P3VEC("input dislocation: ", defect->orient); P3VEC("input burgers: ", defect->burgers); P3VEC("transformed dislocation: ", v); P3VEC("transformed burgers: ", b); #endif /* get the transformed lattice vectors, so we know how deep the cell needs to be */ plane = plane_new(defect->orient, source); VEC3SET(x1, plane->lattice[0], plane->lattice[3], plane->lattice[6]); VEC3SET(x2, plane->lattice[1], plane->lattice[4], plane->lattice[7]); VEC3SET(x3, plane->lattice[2], plane->lattice[5], plane->lattice[8]); P3MAT("cell: ", plane->lattice); printf("%f x %f\n", VEC3MAG(x1), VEC3MAG(x2)); mult1 = mult2 = 1; /* check if periodicity along first surface vector needs help */ ARR3SET(x, x3); vector_v_project(x, x1); len = VEC3MAG(x); if (len > FRACTION_TOLERANCE) { printf("non-zero projection of depth onto surface vec 1 = %f\n", len); r = VEC3MAG(x1)/len; mult1 = numeric_make_whole(r); if (!mult1) mult1 = 1; } /* check if periodicity along second surface vector needs help */ ARR3SET(x, x3); vector_v_project(x, x2); len = VEC3MAG(x); if (len > FRACTION_TOLERANCE) { printf("non-zero projection of depth onto surface vec 2 = %f\n", len); r = VEC3MAG(x2)/len; mult2 = numeric_make_whole(r); if (!mult2) mult2 = 1; } /* compute compiance tensor */ if (defect_compliance_get(s, plane, source)) { printf("Failed - terminating.\n"); return; } else { printf("s44 = %f, s55 = %f\n", s[21], s[28]); } gcd = GCD(mult1, mult2); height = mult1 * mult2 / gcd; printf("mult1 = %d, mult2 = %d, gcd = %d\n", mult1, mult2, gcd); printf("height = %d\n", height); /* DEBUG - test that our new depth vector (in z) will hit a lattice point */ ARR3SET(w, x3); VEC3MUL(w, height); vector_v_project(w, x1); printf("lattice point along surface vector 1: %f\n", VEC3MAG(w)/VEC3MAG(x1)); ARR3SET(w, x3); VEC3MUL(w, height); vector_v_project(w, x2); printf("lattice point along surface vector 2: %f\n", VEC3MAG(w)/VEC3MAG(x2)); /* CURRENT - cope with reduced orientation vector (eg 220 = halved 110) */ gcd = GCD(GCD(defect->orient[0], defect->orient[1]), GCD(defect->orient[1], defect->orient[2])); height /= gcd; /* TODO - if threaded - do this in the gui *before* defect_new() is called */ model = model_new(); /* I thought we could use the true cell stuff, but it's too messy */ /* given that the dislocation is based on distance from cylinder center */ source->surface.true_cell = FALSE; ARR3SET(model->surface.miller, defect->orient); model->surface.region[0] = height; model->surface.region[1] = 0; model->surface.shift = 0.0; generate_surface(source, model); /* model is fractional - ie the transformed unit cell */ if (defect->cleave) model->surface.ignore_bonding = TRUE; matrix_lattice_init(model); /* convert fractional origin shift to cartesian */ printf("f origin: %f,%f\n", defect->origin[0], defect->origin[1]); o[0] = plane->lattice[0] * defect->origin[0] + plane->lattice[1] * defect->origin[1]; o[1] = plane->lattice[3] * defect->origin[0] + plane->lattice[4] * defect->origin[1]; printf("c origin: %f,%f\n", o[0], o[1]); defect_make_cylinder(o, defect->region[0], defect->region[1], model); /* coordinate dislocation */ if (via(v, b, 3) < 0.001) { printf("creating SCREW dislocation...\n"); defect_screw_dislocate(s, b, model); } else { printf("TODO - create EDGE dislocation...\n"); } /* CURRENT - rotate so that z (ie defect orientation) points along x */ VEC3SET(&m[0], 0.0, 0.0, 1.0); VEC3SET(&m[3], 0.0, 1.0, 0.0); VEC3SET(&m[6], -1.0, 0.0, 0.0); for (list=model->cores ; list ; list=g_slist_next(list)) { core = list->data; vecmat(m, core->x); if (core->shell) { shell = core->shell; vecmat(m, shell->x); } } /* display the model - if threaded have to shunt this elsewhere */ sysenv.mal = g_slist_append(sysenv.mal, model); /* all solated cluster for debugging purposes */ if (defect->cluster) { matrix_identity(model->latmat); model->periodic = 0; } else { /* setup the lattice matrix */ matrix_identity(model->latmat); model->periodic = 1; /* get z projected length of depth vector */ VEC3SET(x, 0.0, 0.0, 1.0); vector_v_project(x3, x); model->latmat[0] = height * VEC3MAG(x3); } plane_free(plane); model->fractional = FALSE; model->id = GULP; gulp_data_copy(source, model); model_prep(model); sysenv.active_model = model; tree_model_add(model); tree_select_active(); }