OSDN Git Service

Molecule#cell_flexibility, set_cell_flexibility are obsolete, and the unit cell is...
authortoshinagata1964 <toshinagata1964@a2be9bc6-48de-4e38-9406-05402d4bc13c>
Fri, 19 Oct 2012 11:46:00 +0000 (11:46 +0000)
committertoshinagata1964 <toshinagata1964@a2be9bc6-48de-4e38-9406-05402d4bc13c>
Fri, 19 Oct 2012 11:46:00 +0000 (11:46 +0000)
git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/molby/trunk@297 a2be9bc6-48de-4e38-9406-05402d4bc13c

Documents/src/molby_rb/Molecule.html
MolLib/MD/MDCore.c
MolLib/MolAction.c
MolLib/MolAction.h
MolLib/Molecule.c
MolLib/Molecule.h
MolLib/Ruby_bind/ruby_bind.c

index 72773b9..85911c0 100644 (file)
@@ -688,13 +688,12 @@ Returns the unit cell parameters. If a unit cell is not set, returns nil. Alpha/
 <a name="M000236"></a>
 <div class="method-heading">
 <span class="method-name">cell = [a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]]<br />
-set_cell([a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]], flag = nil)<br />
+set_cell([a, b, c, alpha, beta, gamma[, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]], convert_coord = nil)<br />
 </span>
 </div>
 <div class="method-description">
 <p>
-Set the unit cell parameters. Alpha/beta/gamma are in degree. If the right-hand value (or the first argument) is nil, then clear the current unit cell. If the second argument is given as non-nil, then
-the coordinates are transformed so that the fractional coordinates remain the same. If the cell parameters are given as an array of 12 floats, then the second half of the array is to represent the sigma value (that are common in crystallographic data). This operation is undoable.
+Set the unit cell parameters. Alpha/beta/gamma are in degree. If the right-hand value (or the first argument) is nil, then clear the current unit cell. If the cell parameters are given as an array of 12 floats, then the second half of the array is to represent the sigma value (that are common in crystallographic data). Convert_coord is a flag to specify that the coordinates should be transformed so that the fractional coordinates remain the same. This operation is undoable.
 </p>
 <p>
 <i>See Also:</i> <a href="Molecule.html#M000238">Molecule#box</a>, <a href="Molecule.html#M000239">Molecule#box=</a>, <a href="Molecule.html#M000235">Molecule#cell</a>
@@ -710,7 +709,7 @@ the coordinates are transformed so that the fractional coordinates remain the sa
 </div>
 <div class="method-description">
 <p>
-Returns whether the unit cell is flexible or not.
+Obsolete. Now the unit cell is always flexible (i.e. different frames can have different unit cell)
 </p>
 </div>
 </div>
@@ -724,7 +723,36 @@ set_cell_flexibility(bool)
 </div>
 <div class="method-description">
 <p>
-Set whether the unit cell is flexible or not.
+Obsolete. Now the unit cell is always flexible (i.e. different frames can have different unit cell)
+</p>
+</div>
+</div>
+
+<div id="method-M000237" class="method-detail">
+<a name="cell_periodicity"></a>
+<div class="method-heading">
+<span class="method-name">cell_periodicity &rarr; [n1, n2, n3] or nil<br />
+</span>
+</div>
+<div class="method-description">
+<p>
+Get flags denoting whether the cell is periodic along the a/b/c axes. If the cell is not defined, nil is returned.
+</p>
+</div>
+</div>
+
+<div id="method-M000237" class="method-detail">
+<a name="set_cell_periodicity"></a>
+<div class="method-heading">
+<span class="method-name">self.cell_periodicity = [n1, n2, n3] or Integer or nil<br />
+set_cell_periodicity([n1, n2, n3] or Integer or nil)
+</span>
+</div>
+<div class="method-description">
+<p>
+Set whether the cell is periodic along the a/b/c axes. If an integer is given as an argument, its bits 2/1/0 (from the lowest) correspond to the a/b/c axes. Nil is equivalent to [0, 0, 0].
+If cell is not defined, exception is raised.
+This operation is undoable.
 </p>
 </div>
 </div>
index 8cf6340..74ad09c 100644 (file)
@@ -3227,7 +3227,7 @@ md_update_cell(MDArena *arena)
 void
 md_set_cell(MDArena *arena)
 {
-       Molecule *mol = arena->mol;
+       Molecule *mol = arena->xmol;
        if (mol == NULL)
                return;
        if (mol->cell != NULL) {
index 923eb56..baf1550 100644 (file)
@@ -56,10 +56,11 @@ const char *gMolActionExpandBySymmetry = "expandSym:Giiii;I";
 const char *gMolActionDeleteSymmetryOperation = "deleteSymop";
 const char *gMolActionAddSymmetryOperation = "addSymop:t";
 const char *gMolActionSetCell         = "setCell:Di";
+const char *gMolActionSetCellPeriodicity = "setCellPeriodicity:i";
 const char *gMolActionSetBox          = "setBox:vvvvii";
 const char *gMolActionClearBox        = "clearBox";
-const char *gMolActionSetBoxForFrames = "setBoxForFrames:V";
-const char *gMolActionSetCellFlexibility = "setCellFlexibility:i";
+/*const char *gMolActionSetBoxForFrames = "setBoxForFrames:V"; */
+/*const char *gMolActionSetCellFlexibility = "setCellFlexibility:i"; */
 const char *gMolActionAddParameters   = "addParameters:iGU";
 const char *gMolActionDeleteParameters = "deleteParameters:iG";
 const char *gMolActionAmendBySymmetry = "amendBySymmetry:G;G";
@@ -1312,11 +1313,12 @@ s_MolActionSetCell(Molecule *mol, MolAction *action, MolAction **actp)
 {
        double *dp, d[12];
        Vector vecs[4];
-       Int flags;
+       Int oflags;
        Int convertCoord, n1, n2;
        if (mol->cell == NULL) {
                d[0] = 0.0;
                n1 = 0;
+               oflags = 0;
        } else {
                for (n1 = 0; n1 < 6; n1++)
                        d[n1] = mol->cell->cell[n1];
@@ -1326,7 +1328,7 @@ s_MolActionSetCell(Molecule *mol, MolAction *action, MolAction **actp)
                }
                memmove(vecs, mol->cell->axes, sizeof(Vector) * 3);
                vecs[3] = mol->cell->origin;
-               flags = (mol->cell->flags[0] != 0) * 4 + (mol->cell->flags[1] != 0) * 2 + (mol->cell->flags[2] != 0);
+               oflags = (mol->cell->flags[0] != 0) * 4 + (mol->cell->flags[1] != 0) * 2 + (mol->cell->flags[2] != 0);
        }
        convertCoord = action->args[1].u.ival;
        dp = action->args[0].u.arval.ptr;
@@ -1344,7 +1346,7 @@ s_MolActionSetCell(Molecule *mol, MolAction *action, MolAction **actp)
        if (n1 == 0)
                *actp = MolActionNew(gMolActionClearBox);
        else {
-               *actp = MolActionNew(gMolActionSetBox, &vecs[0], &vecs[1], &vecs[2], &vecs[3], flags, convertCoord);
+               *actp = MolActionNew(gMolActionSetBox, &vecs[0], &vecs[1], &vecs[2], &vecs[3], oflags, convertCoord);
                if (n1 > 6) {
                        /*  Two undo actions are needed: first is for restore the cell vectors, and second is for restore the sigmas  */
                        MolAction *act2;
@@ -1357,6 +1359,21 @@ s_MolActionSetCell(Molecule *mol, MolAction *action, MolAction **actp)
 }
 
 static int
+s_MolActionSetCellPeriodicity(Molecule *mol, MolAction *action, MolAction **actp)
+{
+       Int flags, oflags;
+       if (mol->cell == NULL)
+               return 0;  /*  Do nothing  */
+       oflags = (mol->cell->flags[0] != 0) * 4 + (mol->cell->flags[1] != 0) * 2 + (mol->cell->flags[2] != 0);
+       flags = action->args[0].u.ival;
+       mol->cell->flags[0] = ((flags & 4) != 0);
+       mol->cell->flags[1] = ((flags & 2) != 0);
+       mol->cell->flags[2] = ((flags & 1) != 0);
+       *actp = MolActionNew(gMolActionSetCellPeriodicity, oflags);
+       return 0;
+}
+
+static int
 s_MolActionSetBox(Molecule *mol, MolAction *action, MolAction **actp)
 {
        Int n1, n2;
@@ -1400,6 +1417,7 @@ s_MolActionSetBox(Molecule *mol, MolAction *action, MolAction **actp)
 }
 
 /*  This action is used for undoing "cell_flexibility = false"  */
+/*
 static int
 s_MolActionSetBoxForFrames(Molecule *mol, MolAction *action, MolAction **actp)
 {
@@ -1407,15 +1425,15 @@ s_MolActionSetBoxForFrames(Molecule *mol, MolAction *action, MolAction **actp)
        Vector *vp1, *vp2;
        n2 = MoleculeGetNumberOfFrames(mol);
        if (n2 == 0 || mol->cell == NULL)
-               return 0;  /*  Do nothing  */
+               return 0;  //  Do nothing 
        n1 = action->args[0].u.arval.nitems / 4;
        vp1 = (Vector *)(action->args[0].u.arval.ptr);
        if (mol->nframe_cells < n2) {
-               /*  Expand the array before processing  */
+               //  Expand the array before processing 
                i = mol->nframe_cells * 4;
                AssignArray(&(mol->frame_cells), &(mol->nframe_cells), sizeof(Vector) * 4, n2 - 1, NULL);
                while (i < n2 * 4) {
-                       /*  Copy the current cell  */
+                       //  Copy the current cell 
                        mol->frame_cells[i++] = mol->cell->axes[0];
                        mol->frame_cells[i++] = mol->cell->axes[1];
                        mol->frame_cells[i++] = mol->cell->axes[2];
@@ -1429,23 +1447,24 @@ s_MolActionSetBoxForFrames(Molecule *mol, MolAction *action, MolAction **actp)
        *actp = MolActionNew(gMolActionSetBoxForFrames, n2 * 4, vp2);
        free(vp2);
 
-       /*  Set the current cell (no change on the periodic flags)  */
+       //  Set the current cell (no change on the periodic flags)
        vp2 = mol->frame_cells + mol->cframe * 4;
        MoleculeSetPeriodicBox(mol, vp2, vp2 + 1, vp2 + 2, vp2 + 3, mol->cell->flags, 0);
        
        return 0;
-}
+} */
 
+/*
 static int
 s_MolActionSetCellFlexibility(Molecule *mol, MolAction *action, MolAction **actp)
 {
        Int n1;
        n1 = action->args[0].u.ival;
        if ((n1 != 0) == (mol->useFlexibleCell != 0))
-               return 0;  /*  Do nothing  */
+               return 0;  //  Do nothing
        mol->useFlexibleCell = (n1 != 0);
        if (n1 == 0) {
-               /*  Clear the existing cells, and register undo  */
+               //  Clear the existing cells, and register undo
                if (mol->nframe_cells > 0) {
                        MolAction *act2 = MolActionNew(gMolActionSetBoxForFrames, mol->nframe_cells * 4, mol->frame_cells);
                        MolActionSetFrame(act2, mol->cframe);
@@ -1456,15 +1475,15 @@ s_MolActionSetCellFlexibility(Molecule *mol, MolAction *action, MolAction **actp
                mol->frame_cells = NULL;
                mol->nframe_cells = 0;
        } else {
-               /*  Allocate cells for all frames and copy the current cell  */
+               //  Allocate cells for all frames and copy the current cell
                Int i, nframes = MoleculeGetNumberOfFrames(mol);
                if (nframes != 0 && mol->cell != NULL) {
                        if (mol->nframe_cells < nframes) {
-                               /*  Expand the array  */
+                               //  Expand the array
                                AssignArray(&(mol->frame_cells), &(mol->nframe_cells), sizeof(Vector) * 4, nframes - 1, NULL);
                        }
-                       /*  Copy the current cell  */
-                       /*  (No undo action is registered; actually, the frame_cells array should be empty)  */
+                       //  Copy the current cell 
+                       //  (No undo action is registered; actually, the frame_cells array should be empty) 
                        for (i = 0; i < nframes; i++) {
                                mol->frame_cells[i * 4] = mol->cell->axes[0];
                                mol->frame_cells[i * 4 + 1] = mol->cell->axes[1];
@@ -1476,6 +1495,7 @@ s_MolActionSetCellFlexibility(Molecule *mol, MolAction *action, MolAction **actp
        *actp = MolActionNew(gMolActionSetCellFlexibility, (n1 == 0));
        return 0;
 }
+*/
 
 static int
 s_MolActionAddParameters(Molecule *mol, MolAction *action, MolAction **actp)
@@ -1770,7 +1790,13 @@ MolActionPerform(Molecule *mol, MolAction *action)
                        return result;
                if (mol->arena != NULL)
                        md_set_cell(mol->arena);
-               needsRebuildMDArena = 1;
+               needsSymmetryAmendment = 1;
+       } else if (strcmp(action->name, gMolActionSetCellPeriodicity) == 0) {
+               if ((result = s_MolActionSetCellPeriodicity(mol, action, &act2)) != 0)
+                       return result;
+               if (mol->arena != NULL)
+                       md_set_cell(mol->arena);
+               needsSymmetryAmendment = 1;
        } else if (strcmp(action->name, gMolActionSetBox) == 0) {
                if ((result = s_MolActionSetBox(mol, action, &act2)) != 0)
                        return result;
@@ -1783,12 +1809,12 @@ MolActionPerform(Molecule *mol, MolAction *action)
                if (mol->arena != NULL)
                        md_set_cell(mol->arena);
                needsSymmetryAmendment = 1;
-       } else if (strcmp(action->name, gMolActionSetBoxForFrames) == 0) {
+/*     } else if (strcmp(action->name, gMolActionSetBoxForFrames) == 0) {
                if ((result = s_MolActionSetBoxForFrames(mol, action, &act2)) != 0)
-                       return result;
-       } else if (strcmp(action->name, gMolActionSetCellFlexibility) == 0) {
+                       return result; */
+/*     } else if (strcmp(action->name, gMolActionSetCellFlexibility) == 0) {
                if ((result = s_MolActionSetCellFlexibility(mol, action, &act2)) != 0)
-                       return result;
+                       return result; */
        } else if (strcmp(action->name, gMolActionAddParameters) == 0) {
                if ((result = s_MolActionAddParameters(mol, action, &act2)) != 0)
                        return result;
index 2523677..9247b35 100644 (file)
@@ -57,10 +57,11 @@ extern const char *gMolActionExpandBySymmetry;
 extern const char *gMolActionDeleteSymmetryOperation;
 extern const char *gMolActionAddSymmetryOperation;
 extern const char *gMolActionSetCell;
+extern const char *gMolActionSetCellPeriodicity;
 extern const char *gMolActionSetBox;
 extern const char *gMolActionClearBox;
-extern const char *gMolActionSetBoxForFrames;
-extern const char *gMolActionSetCellFlexibility;
+/*extern const char *gMolActionSetBoxForFrames; */
+/*extern const char *gMolActionSetCellFlexibility; */
 extern const char *gMolActionAddParameters;
 extern const char *gMolActionDeleteParameters;
 extern const char *gMolActionAmendBySymmetry;
index 531301a..99b70ad 100755 (executable)
@@ -332,6 +332,7 @@ Molecule *
 MoleculeInitWithMolecule(Molecule *mp2, const Molecule *mp)
 {
        int i;
+       MoleculeFlushFrames(mp);
        MoleculeInitWithAtoms(mp2, mp->atoms, mp->natoms);
        if (mp->nbonds > 0) {
                if (NewArray(&mp2->bonds, &mp2->nbonds, sizeof(Int)*2, mp->nbonds) == NULL)
@@ -376,7 +377,7 @@ MoleculeInitWithMolecule(Molecule *mp2, const Molecule *mp)
                memmove(mp2->pibonds, mp->pibonds, sizeof(Int) * 4 * mp->npibonds);
        }
        
-       mp2->useFlexibleCell = mp->useFlexibleCell;
+/*     mp2->useFlexibleCell = mp->useFlexibleCell; */
        if (mp->nframe_cells > 0) {
                if (NewArray(&mp2->frame_cells, &mp2->nframe_cells, sizeof(Vector) * 4, mp->nframe_cells) == NULL)
                        goto error;
@@ -1266,7 +1267,7 @@ MoleculeLoadMbsfFile(Molecule *mp, const char *fname, char *errbuf, int errbufsi
                } else if (strcmp(buf, "!:frame_periodic_boxes") == 0) {
                        Vector vs[5];
                        i = 0;
-                       mp->useFlexibleCell = 1;  /*  The presence of this block causes asserting this flag  */
+               /*      mp->useFlexibleCell = 1;  *//*  The presence of this block causes asserting this flag  */
                        while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
                                if (buf[0] == '!')
                                        continue;
@@ -3901,7 +3902,7 @@ MoleculeWriteToMbsfFile(Molecule *mp, const char *fname, char *errbuf, int errbu
                fprintf(fp, "\n");
        }
        
-       if (mp->useFlexibleCell != 0) {
+       if (mp->nframe_cells > 0) {
                fprintf(fp, "!:frame_periodic_boxes\n");
                fprintf(fp, "! ax ay az; bx by bz; cx cy cz; ox oy oz\n");
                for (i = 0; i < mp->nframe_cells * 4; i++) {
@@ -9747,8 +9748,8 @@ MoleculeInsertFrames(Molecule *mp, IntGroup *group, const Vector *inFrame, const
                        vp[j] = ap->r;
                ap->frames = vp;
        }
-       if (mp->cell != NULL && (mp->useFlexibleCell || inFrameCell != NULL)) {
-               mp->useFlexibleCell = 1;
+       if (mp->cell != NULL && inFrameCell != NULL) {
+       /*      mp->useFlexibleCell = 1; */
                vp = mp->frame_cells;
                AssignArray(&mp->frame_cells, &mp->nframe_cells, sizeof(Vector) * 4, n_new - 1, NULL);
                if (vp == NULL) {
index 678465e..c3575c4 100755 (executable)
@@ -283,7 +283,7 @@ typedef struct Molecule {
                                                         recalculated from the atoms if it is -1  */
        Int    cframe;       /*  The current frame number  */
 
-       Byte   useFlexibleCell;
+/*     Byte   useFlexibleCell;  *//*  Obsolete (since 0.6.5; unit cell is frame dependent in all cases)  */
        Int    nframe_cells;
        Vector *frame_cells; /*  The cell vectors for frames; (nframe_cells*4) array of Vectors  */
 
index 5324880..669219b 100644 (file)
@@ -5576,59 +5576,43 @@ s_Molecule_Cell(VALUE self)
 /*
  *  call-seq:
  *     cell = [a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]]
- *     set_cell([a, b, c, alpha, beta, gamma[, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]], flag = nil)
+ *     set_cell([a, b, c, alpha, beta, gamma[, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]], convert_coord = nil)
  *
  *  Set the unit cell parameters. If the cell value is nil, then clear the current cell.
-    If the given argument has 12 members, then the second half of the parameters represents the sigma values.
-    This operation is undoable. If the second argument is given as non-nil, then 
-       the coordinates are transformed so that the fractional coordinates remain the same.
+    If the given argument has 12 or more members, then the second half of the parameters represents the sigma values.
+    This operation is undoable.
+    Convert_coord is a flag to specify that the coordinates should be transformed so that the fractional coordinates remain the same.
  */
 static VALUE
 s_Molecule_SetCell(int argc, VALUE *argv, VALUE self)
 {
     Molecule *mol;
-       VALUE val, fval;
-       int i, flag, n;
+       VALUE val, cval;
+       int i, convert_coord, n;
        double d[12];
     Data_Get_Struct(self, Molecule, mol);
-       rb_scan_args(argc, argv, "11", &val, &fval);
-       flag = RTEST(fval);
+       rb_scan_args(argc, argv, "11", &val, &cval);
        if (val == Qnil) {
-               MolActionCreateAndPerform(mol, gMolActionSetCell, 0, d, flag);
-       //      MoleculeSetCell(mol, 1, 1, 1, 90, 90, 90);
-               return Qnil;
+               n = 0;
+       } else {
+               int len;
+               val = rb_ary_to_ary(val);
+               len = RARRAY_LEN(val);
+               if (len >= 12) {
+                       n = 12;
+               } else if (len >= 6) {
+                       n = 6;
+               } else rb_raise(rb_eMolbyError, "too few members for cell parameters (6 or 12 required)");
+               for (i = 0; i < n; i++)
+                       d[i] = NUM2DBL(rb_Float((RARRAY_PTR(val))[i]));
        }
-       val = rb_ary_to_ary(val);
-       if (RARRAY_LEN(val) >= 12) {
-               n = 12;
-       } else if (RARRAY_LEN(val) >= 6) {
-               n = 6;
-       } else rb_raise(rb_eMolbyError, "too few members for cell parameters (6 or 12 required)");
-       for (i = 0; i < n; i++)
-               d[i] = NUM2DBL(rb_Float((RARRAY_PTR(val))[i]));
-       MolActionCreateAndPerform(mol, gMolActionSetCell, n, d, flag);
+       convert_coord = (RTEST(cval) ? 1 : 0);
+       MolActionCreateAndPerform(mol, gMolActionSetCell, n, d, convert_coord);
        return val;
 }
 
 /*
  *  call-seq:
- *     cell_transform -> Transform
- *
- *  Get the transform matrix that converts internal coordinates to cartesian coordinates.
- *  If cell is not defined, nil is returned.
- */
-static VALUE
-s_Molecule_CellTransform(VALUE self)
-{
-    Molecule *mol;
-    Data_Get_Struct(self, Molecule, mol);
-       if (mol == NULL || mol->cell == NULL)
-               return Qnil;
-       return ValueFromTransform(&(mol->cell->tr));
-}
-
-/*
- *  call-seq:
  *     box -> [avec, bvec, cvec, origin, flags]
  *
  *  Get the unit cell information in the form of a periodic bounding box.
@@ -5660,14 +5644,14 @@ s_Molecule_Box(VALUE self)
  *     set_box
  *
  *  Set the unit cell parameters. Avec, bvec, and cvec can be either a Vector3D or a number.
   If it is a number, the x/y/z axis vector is multiplied with the given number and used
   as the box vector.
   Flags, if present, is a 3-member array of Integers defining whether the system is
   periodic along the axis.
   If convert_coordinates is true, then the coordinates are converted so that the fractional coordinates remain the same.
   In the second form, an isotropic box with cell-length d is set.
   In the third form, the existing box is cleared.
   Note: the sigma of the cell parameters is not cleared unless the periodic box itself is cleared.
+ If it is a number, the x/y/z axis vector is multiplied with the given number and used
+ as the box vector.
+ Flags, if present, is a 3-member array of Integers defining whether the system is
+ periodic along the axis.
+ If convert_coordinates is true, then the coordinates are converted so that the fractional coordinates remain the same.
+ In the second form, an isotropic box with cell-length d is set.
+ In the third form, the existing box is cleared.
+ Note: the sigma of the cell parameters is not cleared unless the periodic box itself is cleared.
  */
 static VALUE
 s_Molecule_SetBox(VALUE self, VALUE aval)
@@ -5681,6 +5665,11 @@ s_Molecule_SetBox(VALUE self, VALUE aval)
        Double d;
        int i, convertCoordinates = 0;
     Data_Get_Struct(self, Molecule, mol);
+       if (aval == Qnil) {
+               MolActionCreateAndPerform(mol, gMolActionClearBox);
+               return self;
+       }
+       aval = rb_ary_to_ary(aval);
        for (i = 0; i < 6; i++) {
                if (i < RARRAY_LEN(aval))
                        v[i] = (RARRAY_PTR(aval))[i];
@@ -5726,6 +5715,59 @@ s_Molecule_SetBox(VALUE self, VALUE aval)
 
 /*
  *  call-seq:
+ *     cell_periodicity -> [n1, n2, n3]
+ *
+ *  Get flags denoting whether the cell is periodic along the a/b/c axes. If the cell is not defined
+ *  nil is returned.
+ */
+static VALUE
+s_Molecule_CellPeriodicity(VALUE self)
+{
+    Molecule *mol;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->cell == NULL)
+               return Qnil;
+       return rb_ary_new3(3, INT2FIX((int)mol->cell->flags[0]), INT2FIX((int)mol->cell->flags[1]), INT2FIX((int)mol->cell->flags[2]));
+}
+
+/*
+ *  call-seq:
+ *     self.cell_periodicity = [n1, n2, n3] or Integer or nil
+ *     set_cell_periodicity = [n1, n2, n3] or Integer or nil
+ *
+ *  Set whether the cell is periodic along the a/b/c axes. If an integer is given as an argument,
+ *  its bits 2/1/0 (from the lowest) correspond to the a/b/c axes. Nil is equivalent to [0, 0, 0].
+ *  If cell is not defined, exception is raised.
+ *  This operation is undoable.
+ */
+static VALUE
+s_Molecule_SetCellPeriodicity(VALUE self, VALUE arg)
+{
+    Molecule *mol;
+       Int flag;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->cell == NULL)
+               rb_raise(rb_eMolbyError, "periodic cell is not defined");
+       if (arg == Qnil)
+               flag = 0;
+       else if (rb_obj_is_kind_of(arg, rb_cNumeric))
+               flag = NUM2INT(rb_Integer(arg));
+       else {
+               Int i;
+               VALUE arg0;
+               arg = rb_ary_to_ary(arg);
+               for (i = 0; i < 3 && i < RARRAY_LEN(arg); i++) {
+                       arg0 = RARRAY_PTR(arg)[i];
+                       if (arg0 != Qnil && arg0 != Qfalse && arg0 != INT2FIX(0))
+                               flag |= (1 << (2 - i));
+               }
+       }
+       MolActionCreateAndPerform(mol, gMolActionSetCellPeriodicity, flag);
+       return arg;
+}
+
+/*
+ *  call-seq:
  *     cell_flexibility -> bool
  *
  *  Returns the unit cell is flexible or not
@@ -5733,13 +5775,15 @@ s_Molecule_SetBox(VALUE self, VALUE aval)
 static VALUE
 s_Molecule_CellFlexibility(VALUE self)
 {
-    Molecule *mol;
+       rb_warn("cell_flexibility is obsolete (unit cell is always frame dependent)");
+       return Qtrue;
+/*    Molecule *mol;
     Data_Get_Struct(self, Molecule, mol);
        if (mol->cell == NULL)
                return Qfalse;
        if (mol->useFlexibleCell)
                return Qtrue;
-       else return Qfalse;
+       else return Qfalse; */
 }
 
 /*
@@ -5752,10 +5796,29 @@ s_Molecule_CellFlexibility(VALUE self)
 static VALUE
 s_Molecule_SetCellFlexibility(VALUE self, VALUE arg)
 {
-    Molecule *mol;
+       rb_warn("set_cell_flexibility is obsolete (unit cell is always frame dependent)");
+       return self;
+/*    Molecule *mol;
     Data_Get_Struct(self, Molecule, mol);
        MolActionCreateAndPerform(mol, gMolActionSetCellFlexibility, RTEST(arg) != 0);
-       return self;
+       return self; */
+}
+
+/*
+ *  call-seq:
+ *     cell_transform -> Transform
+ *
+ *  Get the transform matrix that converts internal coordinates to cartesian coordinates.
+ *  If cell is not defined, nil is returned.
+ */
+static VALUE
+s_Molecule_CellTransform(VALUE self)
+{
+    Molecule *mol;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol == NULL || mol->cell == NULL)
+               return Qnil;
+       return ValueFromTransform(&(mol->cell->tr));
 }
 
 /*
@@ -9845,10 +9908,13 @@ Init_Molby(void)
        rb_define_method(rb_cMolecule, "cell", s_Molecule_Cell, 0);
        rb_define_method(rb_cMolecule, "cell=", s_Molecule_SetCell, -1);
        rb_define_alias(rb_cMolecule, "set_cell", "cell=");
-       rb_define_method(rb_cMolecule, "cell_transform", s_Molecule_CellTransform, 0);
        rb_define_method(rb_cMolecule, "box", s_Molecule_Box, 0);
        rb_define_method(rb_cMolecule, "box=", s_Molecule_SetBox, 1);
        rb_define_method(rb_cMolecule, "set_box", s_Molecule_SetBox, -2);
+       rb_define_method(rb_cMolecule, "cell_transform", s_Molecule_CellTransform, 0);
+       rb_define_method(rb_cMolecule, "cell_periodicity", s_Molecule_CellPeriodicity, 0);
+       rb_define_method(rb_cMolecule, "cell_periodicity=", s_Molecule_SetCellPeriodicity, 1);
+       rb_define_alias(rb_cMolecule, "set_cell_periodicity", "cell_periodicity=");
        rb_define_method(rb_cMolecule, "cell_flexibility", s_Molecule_CellFlexibility, 0);
        rb_define_method(rb_cMolecule, "cell_flexibility=", s_Molecule_SetCellFlexibility, 1);
        rb_define_alias(rb_cMolecule, "set_cell_flexibility", "cell_flexibility=");