5 * Created by Toshi Nagata on 07/11/09.
6 * Copyright 2007-2008 Toshi Nagata. All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
19 #include "ruby_dialog.h"
20 #include "../MD/MDCore.h"
27 #include <version.h> /* for Ruby version */
28 #include <node.h> /* for rb_add_event_hook() */
30 #if defined(__WXMAC__) || defined(__CMDMAC__)
31 #define USE_PTHREAD_FOR_TIMER 1
35 #if USE_PTHREAD_FOR_TIMER
36 #include <unistd.h> /* for usleep() */
37 #include <pthread.h> /* for pthread */
39 #include <signal.h> /* for sigaction() */
43 #include "../Missing.h"
45 #pragma mark ====== Global Values ======
49 VALUE rb_cMolecule, rb_cMolEnumerable, rb_cAtomRef;
50 VALUE rb_cParameter, rb_cParEnumerable, rb_cParameterRef;
52 VALUE gMolbyBacktrace;
54 int gMolbyRunLevel = 0;
55 int gMolbyIsCheckingInterrupt = 0;
57 char *gRubyVersion, *gRubyCopyright;
60 static VALUE s_ID_equal; /* rb_intern("==") */
62 /* Symbols for atom attributes */
64 s_IndexSym, s_SegSeqSym, s_SegNameSym, s_ResSeqSym,
65 s_ResNameSym, s_NameSym, s_AtomTypeSym, s_ChargeSym,
66 s_WeightSym, s_ElementSym, s_AtomicNumberSym, s_ConnectsSym,
67 s_RSym, s_XSym, s_YSym, s_ZSym,
68 s_FractRSym, s_FractXSym, s_FractYSym, s_FractZSym,
69 s_SigmaSym, s_SigmaXSym, s_SigmaYSym, s_SigmaZSym,
70 s_VSym, s_FSym, s_OccupancySym, s_TempFactorSym,
71 s_AnisoSym, s_SymopSym, s_IntChargeSym, s_FixForceSym,
72 s_FixPosSym, s_ExclusionSym, s_MMExcludeSym, s_PeriodicExcludeSym,
73 s_HiddenSym, s_AnchorListSym;
75 /* Symbols for parameter attributes */
77 s_ParTypeSym, s_AtomTypesSym, s_KSym, s_R0Sym,
78 s_A0Sym, s_MultSym, s_PeriodSym, s_Phi0Sym,
81 /* s_A14Sym, s_B14Sym, */
82 s_Req14Sym, s_Eps14Sym,
83 s_CutoffSym, s_RadiusSym, s_ColorSym, s_FullNameSym,
84 s_CommentSym, s_SourceSym;
88 * Get ary[i] by calling "[]" method
91 Ruby_ObjectAtIndex(VALUE ary, int idx)
93 static ID index_method = 0;
94 if (TYPE(ary) == T_ARRAY) {
95 int len = RARRAY_LEN(ary);
96 if (idx >= 0 && idx < len)
97 return (RARRAY_PTR(ary))[idx];
100 if (index_method == 0)
101 index_method = rb_intern("[]");
102 return rb_funcall(ary, index_method, 1, INT2NUM(idx));
106 Ruby_FileStringValuePtr(VALUE *valp)
109 char *p = strdup(StringValuePtr(*valp));
110 translate_char(p, '/', '\\');
111 *valp = rb_str_new2(p);
113 return StringValuePtr(*valp);
115 return StringValuePtr(*valp);
120 Ruby_NewFileStringValue(const char *fstr)
124 char *p = strdup(fstr);
125 translate_char(p, '\\', '/');
126 retval = rb_str_new2(p);
130 return rb_str_new2(fstr);
135 Ruby_ObjToStringObj(VALUE val)
141 return rb_str_new2(rb_id2name(SYM2ID(val)));
143 return rb_str_to_str(val);
147 #pragma mark ====== Message input/output ======
151 * message_box(str, title, button = nil, icon = :info)
153 * Show a message box.
154 * Buttons: nil (ok and cancel), :ok (ok only), :cancel (cancel only)
155 * Icon: :info, :warning, :error
158 s_Kernel_MessageBox(int argc, VALUE *argv, VALUE self)
160 char *str, *title, *s;
162 VALUE sval, tval, bval, ival;
163 rb_scan_args(argc, argv, "22", &sval, &tval, &bval, &ival);
164 str = StringValuePtr(sval);
165 title = StringValuePtr(tval);
167 bval = Ruby_ObjToStringObj(bval);
168 s = RSTRING_PTR(bval);
169 if (strncmp(s, "ok", 2) == 0)
171 else if (strncmp(s, "cancel", 6) == 0)
174 rb_raise(rb_eMolbyError, "the button specification should be either nil, :ok or :cancel");
177 ival = Ruby_ObjToStringObj(ival);
178 s = RSTRING_PTR(ival);
179 if (strncmp(s, "info", 4) == 0)
181 else if (strncmp(s, "warn", 4) == 0)
183 else if (strncmp(s, "err", 3) == 0)
186 rb_raise(rb_eMolbyError, "the icon specification should be either :info, :warning or :error");
188 MyAppCallback_messageBox(str, title, buttons, icon);
194 * error_message_box(str)
196 * Show an error message box.
199 s_Kernel_ErrorMessageBox(VALUE self, VALUE sval)
201 char *str = StringValuePtr(sval);
202 MyAppCallback_errorMessageBox("%s", str);
208 * ask(prompt, default = nil) -> string
210 * Open a modal dialog and get a line of text.
213 s_Kernel_Ask(int argc, VALUE *argv, VALUE self)
215 volatile VALUE prompt, message;
218 rb_scan_args(argc, argv, "11", &prompt, &message);
219 if (message != Qnil) {
220 strncpy(buf, StringValuePtr(message), sizeof buf - 1);
221 buf[sizeof buf - 1] = 0;
223 retval = MyAppCallback_getTextWithPrompt(StringValuePtr(prompt), buf, sizeof buf);
225 return rb_str_new2(buf);
234 * Put the message in the main text view in black color.
237 s_StandardOutput(VALUE self, VALUE str)
240 MyAppCallback_setConsoleColor(0);
241 n = MyAppCallback_showScriptMessage("%s", StringValuePtr(str));
249 * Put the message in the main text view in red color.
252 s_StandardErrorOutput(VALUE self, VALUE str)
255 MyAppCallback_setConsoleColor(1);
256 n = MyAppCallback_showScriptMessage("%s", StringValuePtr(str));
257 MyAppCallback_setConsoleColor(0);
263 * stdin.gets(rs = $/)
265 * Read one line message via dialog box.
268 s_StandardInputGets(int argc, VALUE *argv, VALUE self)
271 pval = rb_str_new2("Enter a line:");
272 rval = s_Kernel_Ask(1, &pval, self);
275 rb_str_cat2(rval, "\n");
281 * stdin.method_missing(name, args, ...)
283 * Throw an exception, noting only gets and readline are defined.
286 s_StandardInputMethodMissing(int argc, VALUE *argv, VALUE self)
289 rb_scan_args(argc, argv, "10", &nval);
290 rb_raise(rb_eMolbyError, "'%s' is undefined. Only 'gets' and 'readline' can be used for stdin within Molby.", rb_id2name(SYM2ID(nval)));
291 return Qnil; /* Not reached */
294 #pragma mark ====== Track key events ======
296 /* User interrupt handling
297 * User interrupt (command-period on Mac OS) is handled by periodic polling of
298 * key events. This polling should only be enabled during "normal" execution
299 * of scripts and must be disabled when the rest of the application (or Ruby
300 * script itself) is handling GUI. This is ensured by appropriate calls to
301 * enable_interrupt and disable_interrupt. */
303 static VALUE s_interrupt_flag = Qfalse;
306 s_ShowProgressPanel(int argc, VALUE *argv, VALUE self)
308 volatile VALUE message;
310 if (Ruby_GetInterruptFlag() == Qtrue) {
311 rb_scan_args(argc, argv, "01", &message);
313 p = StringValuePtr(message);
316 MyAppCallback_showProgressPanel(p);
322 s_HideProgressPanel(VALUE self)
324 MyAppCallback_hideProgressPanel();
329 s_SetProgressValue(VALUE self, VALUE val)
331 double dval = NUM2DBL(rb_Float(val));
332 MyAppCallback_setProgressValue(dval);
337 s_SetProgressMessage(VALUE self, VALUE msg)
342 else p = StringValuePtr(msg);
343 MyAppCallback_setProgressMessage(p);
348 s_SetInterruptFlag(VALUE self, VALUE val)
352 if (val == Qfalse || val == Qnil)
356 oldval = s_interrupt_flag;
358 s_interrupt_flag = val;
360 s_HideProgressPanel(self);
367 s_GetInterruptFlag(VALUE self)
369 return s_SetInterruptFlag(self, Qundef);
374 s_Ruby_CallMethod(VALUE val)
376 void **ptr = (void **)val;
377 VALUE receiver = (VALUE)ptr[0];
378 ID method_id = (ID)ptr[1];
379 VALUE args = (VALUE)ptr[2];
381 if (method_id == 0) {
382 /* args should be a string, which is evaluated */
383 if (receiver == Qnil) {
384 retval = rb_eval_string(StringValuePtr(args));
386 retval = rb_obj_instance_eval(1, &args, receiver);
389 /* args should be an array of arguments */
390 retval = rb_apply(receiver, method_id, args);
396 Ruby_CallMethodWithInterrupt(VALUE receiver, ID method_id, VALUE args, int *status)
398 VALUE retval, save_interrupt_flag;
400 save_interrupt_flag = s_SetInterruptFlag(Qnil, Qtrue);
401 ptr[0] = (void *)receiver;
402 ptr[1] = (void *)method_id;
403 ptr[2] = (void *)args;
404 MyAppCallback_beginUndoGrouping();
405 retval = rb_protect(s_Ruby_CallMethod, (VALUE)ptr, status);
406 MyAppCallback_endUndoGrouping();
407 s_SetInterruptFlag(Qnil, save_interrupt_flag);
408 MyAppCallback_hideProgressPanel(); /* In case when the progress panel is still onscreen */
\v
414 Ruby_SetInterruptFlag(VALUE val)
416 return s_SetInterruptFlag(Qnil, val);
420 Ruby_GetInterruptFlag(void)
422 return s_SetInterruptFlag(Qnil, Qundef);
427 * check_interrupt -> integer
429 * Returns 1 if interrupted, 0 if not, -1 if interrupt is disabled.
432 s_Kernel_CheckInterrupt(VALUE self)
434 if (Ruby_GetInterruptFlag() == Qfalse)
436 else if (MyAppCallback_checkInterrupt())
438 else return INT2NUM(0);
441 static volatile unsigned long sITimerCount = 0;
444 static HANDLE sITimerEvent;
445 static HANDLE sITimerThread;
446 static int sITimerInterval;
448 static __stdcall unsigned
449 s_ITimerThreadFunc(void *p)
451 while (WaitForSingleObject(sITimerEvent, sITimerInterval) == WAIT_TIMEOUT) {
457 #elif USE_PTHREAD_FOR_TIMER
460 static pthread_t sTimerThread;
462 /* -1: uninitiated; 0: active, 1: inactive, -2: request to terminate */
463 static volatile signed char sTimerFlag = -1;
464 static volatile int sTimerIntervalMicrosec = 0;
467 s_TimerThreadEntry(void *param)
470 usleep(sTimerIntervalMicrosec);
473 else if (sTimerFlag == -2)
482 s_SignalAction(int n)
488 s_SetIntervalTimer(int n, int msec)
492 /* Start interval timer */
493 sITimerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
494 sITimerInterval = msec;
496 sITimerThread = (HANDLE)_beginthreadex(NULL, 0, s_ITimerThreadFunc, NULL, 0, NULL);
499 /* Stop interval timer */
501 SetEvent(sITimerEvent); /* Tell thread to terminate */
503 WaitForSingleObject(sITimerThread, 1000);
504 CloseHandle(sITimerThread);
507 CloseHandle(sITimerEvent);
509 sITimerThread = NULL;
511 #elif USE_PTHREAD_FOR_TIMER
513 if (sTimerFlag == -1) {
514 int status = pthread_create(&sTimerThread, NULL, s_TimerThreadEntry, NULL);
516 fprintf(stderr, "pthread_create failed while setting Ruby interval timer: status = %d\n", status);
519 sTimerFlag = 0; /* Active */
520 sTimerIntervalMicrosec = msec * 1000;
521 } else if (sTimerFlag != -1)
522 sTimerFlag = 1; /* Inactive */
524 static struct itimerval sOldValue;
525 static struct sigaction sOldAction;
526 struct itimerval val;
527 struct sigaction act;
530 act.sa_handler = s_SignalAction;
533 sigaction(SIGALRM, &act, &sOldAction);
534 val.it_value.tv_sec = 0;
535 val.it_value.tv_usec = msec * 1000;
536 val.it_interval.tv_sec = 0;
537 val.it_interval.tv_usec = msec * 1000;
538 setitimer(ITIMER_REAL, &val, &sOldValue);
540 setitimer(ITIMER_REAL, &sOldValue, &val);
541 sigaction(SIGALRM, &sOldAction, &act);
547 s_GetTimerCount(void)
553 s_Event_Callback(rb_event_t event, NODE *node, VALUE self, ID rid, VALUE klass)
555 if (s_interrupt_flag != Qfalse) {
556 static unsigned long sLastTime = 0;
557 unsigned long currentTime;
559 currentTime = s_GetTimerCount();
560 if (currentTime != sLastTime) {
561 sLastTime = currentTime;
562 gMolbyIsCheckingInterrupt = 1;
563 flag = MyAppCallback_checkInterrupt();
564 gMolbyIsCheckingInterrupt = 0;
566 s_SetInterruptFlag(Qnil, Qfalse);
573 #pragma mark ====== Menu handling ======
577 * register_menu(title, method)
579 * Register the method (specified as a symbol) in the script menu.
580 * The method must be either an instance method of Molecule with no argument,
581 * or a class method of Molecule with one argument (the current molecule).
582 * The menu associated with the class method can be invoked even when no document
583 * is open (the argument is set to Qnil in this case). On the other hand, the
584 * menu associated with the instance method can only be invoked when at least one
585 * document is active.
588 s_Kernel_RegisterMenu(VALUE self, VALUE title, VALUE method)
590 if (TYPE(method) == T_SYMBOL) {
591 method = rb_funcall(method, rb_intern("to_s"), 0);
593 MyAppCallback_registerScriptMenu(StringValuePtr(method), StringValuePtr(title));
598 s_Kernel_LookupMenu(VALUE self, VALUE title)
600 int n = MyAppCallback_lookupScriptMenu(StringValuePtr(title));
605 s_Ruby_methodType_sub(VALUE data)
607 const char **p = (const char **)data;
608 VALUE klass = rb_const_get(rb_cObject, rb_intern(p[0]));
609 ID mid = rb_intern(p[1]);
611 if (rb_funcall(klass, rb_intern("method_defined?"), 1, ID2SYM(mid)) != Qfalse)
613 else if (rb_respond_to(klass, mid))
616 return INT2FIX(ival);
619 /* Returns 1 if the class defines the instance method with the given name, 2 if the class
620 has the singleton method (class method) with the given name, 0 otherwise. */
622 Ruby_methodType(const char *className, const char *methodName)
629 retval = rb_protect(s_Ruby_methodType_sub, (VALUE)p, &status);
631 return FIX2INT(retval);
637 * execute_script_file(fname)
639 * Execute the script in the given file. If a molecule is active, then
640 * the script is evaluated as Molecule.current.instance_eval(script).
641 * Before entering the script, the current directory is set to the parent
642 * directory of the script.
645 s_Kernel_ExecuteScript(VALUE self, VALUE fname)
648 VALUE retval = (VALUE)MyAppCallback_executeScriptFromFile(StringValuePtr(fname), &status);
649 if (retval == (VALUE)6 && status == -1)
650 rb_raise(rb_eMolbyError, "Cannot open script file: %s", StringValuePtr(fname));
660 * Get the directory suitable for storing user documents. On Windows
661 * it is the home directory + "My Documents". On other platforms
662 * it is the home directory.
665 s_Kernel_DocumentHome(VALUE self)
667 char *s = MyAppCallback_getDocumentHomeDir();
668 VALUE retval = Ruby_NewFileStringValue(s);
675 * call_subprocess(cmd, process_name)
677 * Call subprocess. A progress dialog window is displayed, with a message
678 * "Running #{process_name}...".
681 s_Kernel_CallSubProcess(VALUE self, VALUE cmd, VALUE procname)
683 int n = MyAppCallback_callSubProcess(StringValuePtr(cmd), StringValuePtr(procname));
687 #pragma mark ====== User defaults ======
691 * get_global_settings(key)
693 * Get a setting data for key from the application preferences.
696 s_Kernel_GetGlobalSettings(VALUE self, VALUE key)
698 char *p = MyAppCallback_getGlobalSettings(StringValuePtr(key));
700 VALUE retval = rb_eval_string(p);
708 * set_global_settings(key, value)
710 * Set a setting data for key to the application preferences.
713 s_Kernel_SetGlobalSettings(VALUE self, VALUE key, VALUE value)
715 VALUE sval = rb_inspect(value);
716 MyAppCallback_setGlobalSettings(StringValuePtr(key), StringValuePtr(sval));
720 #pragma mark ====== Utility functions (protected funcall) ======
722 struct Ruby_funcall2_record {
730 s_Ruby_funcall2_sub(VALUE data)
732 struct Ruby_funcall2_record *rp = (struct Ruby_funcall2_record *)data;
733 return rb_funcall2(rp->recv, rp->mid, rp->argc, rp->argv);
737 Ruby_funcall2_protect(VALUE recv, ID mid, int argc, VALUE *argv, int *status)
739 struct Ruby_funcall2_record rec;
744 return rb_protect(s_Ruby_funcall2_sub, (VALUE)&rec, status);
747 #pragma mark ====== ParameterRef Class ======
750 s_UnionParFromValue(VALUE self, Int *typep, Int checkEditable)
754 Data_Get_Struct(self, ParameterRef, pref);
756 *typep = pref->parType;
757 if (pref->parType == kElementParType) {
758 up = (UnionPar *)&gElementParameters[pref->idx];
760 up = ParameterRefGetPar(pref);
763 rb_raise(rb_eMolbyError, "Cannot modify parameter because it is internally cached in the MDArena");
764 if (up->bond.src != 0 && up->bond.src != -1)
765 rb_raise(rb_eMolbyError, "Cannot modify parameter because it is not molecule-local");
772 s_RegisterUndoForParameterAttrChange(VALUE self, VALUE key, VALUE val, VALUE oldval, int oldsrc)
776 Data_Get_Struct(self, ParameterRef, pref);
777 if (pref->mol == NULL)
779 up = ParameterRefGetPar(pref);
780 if (key != s_SourceSym)
781 up->bond.src = 0; /* Becomes automatically molecule-local */
782 if (MolActionCallback_isUndoRegistrationEnabled(pref->mol)) {
785 act = MolActionNew(SCRIPT_ACTION("iirri"), "set_parameter_attr", pref->parType, pref->idx, key, oldval, oldsrc);
786 MolActionCallback_registerUndo(pref->mol, act);
787 MoleculeCallback_notifyModification(pref->mol, 0);
788 pref->mol->needsMDRebuild = 1;
793 ValueFromMoleculeWithParameterTypeAndIndex(Molecule *mol, int type, int idx1)
795 ParameterRef *pref = ParameterRefNew(mol, type, idx1);
797 return Data_Wrap_Struct(rb_cParameterRef, 0, (void (*)(void *))ParameterRefRelease, pref);
799 rb_raise(rb_eMolbyError, "Cannot create parameter reference");
803 s_AtomTypeIndexFromValue(VALUE val)
805 if (rb_obj_is_kind_of(val, rb_cNumeric))
808 return AtomTypeEncodeToUInt(StringValuePtr(val));
811 static const char *s_ParameterTypeNames[] = {
812 "bond", "angle", "dihedral", "improper", "vdw", "vdw_pair", "vdw_cutoff", "element"
814 static ID s_ParameterTypeIDs[8] = {0, 0, 0, 0, 0, 0, 0, 0};
817 s_ParTypeFromValue(VALUE val)
821 n = sizeof(s_ParameterTypeNames) / sizeof(s_ParameterTypeNames[0]);
822 if (s_ParameterTypeIDs[0] == 0) {
823 for (i = 0; i < n; i++)
824 s_ParameterTypeIDs[i] = rb_intern(s_ParameterTypeNames[i]);
826 valid = rb_to_id(val);
827 for (i = 0; i < n; i++) {
828 if (valid == s_ParameterTypeIDs[i]) {
830 return kElementParType;
831 else return kFirstParType + i;
834 return kInvalidParType;
841 * Get the index in the parameter list.
843 static VALUE s_ParameterRef_GetIndex(VALUE self) {
845 Data_Get_Struct(self, ParameterRef, pref);
846 return INT2NUM(pref->idx);
853 * Get the parameter type, like "bond", "angle", etc.
855 static VALUE s_ParameterRef_GetParType(VALUE self) {
857 s_UnionParFromValue(self, &tp, 0);
858 if (tp == kElementParType)
859 return rb_str_new2("element");
861 if (tp >= 0 && tp < sizeof(s_ParameterTypeNames) / sizeof(s_ParameterTypeNames[0]))
862 return rb_str_new2(s_ParameterTypeNames[tp]);
863 else rb_raise(rb_eMolbyError, "Internal error: parameter type tag is out of range (%d)", tp);
868 * atom_type -> String or Array of String
869 * atom_types -> String or Array of String
871 * Get the atom types. For a bond parameter, an array of two strings (like ["ca", "ha"])
872 * is returned. For an angle parameter, an array of three strings (like ["ha", "ca", "ha"])
873 * is returned. For a dihedral or improper parameter, an array of four strings is returned.
874 * The atom type may be "X", which is a wildcard that matches any atom type.
876 static VALUE s_ParameterRef_GetAtomTypes(VALUE self) {
881 up = s_UnionParFromValue(self, &tp, 0);
882 n = ParameterGetAtomTypes(tp, up, types);
884 rb_raise(rb_eMolbyError, "invalid member atom_types");
885 for (i = 0; i < n; i++) {
886 if (types[i] >= 0 && types[i] < kAtomTypeMinimum)
887 vals[i] = INT2NUM(types[i]);
889 vals[i] = rb_str_new2(AtomTypeDecodeToString(types[i], NULL));
894 return rb_ary_new4(n, vals);
901 * Get the force constant. Available for bond, angle, dihedral, and improper parameters.
903 static VALUE s_ParameterRef_GetK(VALUE self) {
907 up = s_UnionParFromValue(self, &tp, 0);
910 return rb_float_new(up->bond.k * INTERNAL2KCAL);
912 return rb_float_new(up->angle.k * INTERNAL2KCAL);
913 case kDihedralParType:
914 case kImproperParType:
915 if (up->torsion.mult == 1)
916 return rb_float_new(up->torsion.k[0] * INTERNAL2KCAL);
917 n = up->torsion.mult;
920 for (i = 0; i < n; i++)
921 vals[i] = rb_float_new(up->torsion.k[i] * INTERNAL2KCAL);
922 return rb_ary_new4(n, vals);
924 rb_raise(rb_eMolbyError, "invalid member k");
932 * Get the equilibrium bond length. Only available for bond parameters.
934 static VALUE s_ParameterRef_GetR0(VALUE self) {
937 up = s_UnionParFromValue(self, &tp, 0);
938 if (tp == kBondParType)
939 return rb_float_new(up->bond.r0);
940 else rb_raise(rb_eMolbyError, "invalid member r0");
947 * Get the equilibrium angle (in degree). Only available for angle parameters.
949 static VALUE s_ParameterRef_GetA0(VALUE self) {
952 up = s_UnionParFromValue(self, &tp, 0);
953 if (tp == kAngleParType)
954 return rb_float_new(up->angle.a0 * kRad2Deg);
955 else rb_raise(rb_eMolbyError, "invalid member a0");
962 * Get the multiplicity. Only available for dihedral and improper parameters.
963 * (Note: Implementation of multiple dihedral/improper parameters is not well tested)
965 static VALUE s_ParameterRef_GetMult(VALUE self) {
968 up = s_UnionParFromValue(self, &tp, 0);
969 if (tp == kDihedralParType || tp == kImproperParType)
970 return rb_float_new(up->torsion.mult);
971 else rb_raise(rb_eMolbyError, "invalid member mult");
976 * period -> Integer or Array of Integers
978 * Get the periodicity. Only available for dihedral and improper parameters.
979 * If the multiplicity is larger than 1, then an array of integers is returned.
980 * (Note: Implementation of multiple dihedral/improper parameters is not well tested)
982 static VALUE s_ParameterRef_GetPeriod(VALUE self) {
986 up = s_UnionParFromValue(self, &tp, 0);
987 if (tp == kDihedralParType || tp == kImproperParType) {
988 if (up->torsion.mult == 1)
989 return INT2NUM(up->torsion.period[0]);
990 n = up->torsion.mult;
993 for (i = 0; i < n; i++)
994 vals[i] = INT2NUM(up->torsion.period[i]);
995 return rb_ary_new4(n, vals);
996 } else rb_raise(rb_eMolbyError, "invalid member period");
1001 * phi0 -> Float or Array of Floats
1003 * Get the equilibrium dihedral angle. Only available for dihedral and improper parameters.
1004 * If the multiplicity is larger than 1, then an array of floats is returned.
1005 * (Note: Implementation of multiple dihedral/improper parameters is not well tested)
1007 static VALUE s_ParameterRef_GetPhi0(VALUE self) {
1011 up = s_UnionParFromValue(self, &tp, 0);
1012 if (tp == kDihedralParType || tp == kImproperParType) {
1013 if (up->torsion.mult == 1)
1014 return rb_float_new(up->torsion.phi0[0] * kRad2Deg);
1015 n = up->torsion.mult;
1018 for (i = 0; i < n; i++)
1019 vals[i] = rb_float_new(up->torsion.phi0[i] * kRad2Deg);
1020 return rb_ary_new4(n, vals);
1021 } else rb_raise(rb_eMolbyError, "invalid member phi0");
1028 * Get the "A" value for the van der Waals parameter.
1031 static VALUE s_ParameterRef_GetA(VALUE self) {
1034 up = s_UnionParFromValue(self, &tp, 0);
1035 if (tp == kVdwParType)
1036 return rb_float_new(up->vdw.A);
1037 else if (tp == kVdwPairParType)
1038 return rb_float_new(up->vdwp.A);
1039 else rb_raise(rb_eMolbyError, "invalid member A");
1047 * Get the "B" value for the van der Waals parameter.
1050 static VALUE s_ParameterRef_GetB(VALUE self) {
1053 up = s_UnionParFromValue(self, &tp, 0);
1054 if (tp == kVdwParType)
1055 return rb_float_new(up->vdw.B);
1056 else if (tp == kVdwPairParType)
1057 return rb_float_new(up->vdwp.B);
1058 else rb_raise(rb_eMolbyError, "invalid member B");
1066 * Get the equilibrium radius (half of the minimum energy distance) for the van der Waals parameter.
1068 static VALUE s_ParameterRef_GetReq(VALUE self) {
1071 /* Double a, b, r; */
1073 up = s_UnionParFromValue(self, &tp, 0);
1074 if (tp == kVdwParType) {
1078 } else if (tp == kVdwPairParType) {
1082 } else rb_raise(rb_eMolbyError, "invalid member r_eq");
1083 /* if (a == 0.0 || b == 0.0) */
1084 return rb_float_new(r);
1085 /* else return rb_float_new(pow(2*a/b, 1.0/6.0)); */
1092 * Get the minimum energy for the van der Waals parameter.
1094 static VALUE s_ParameterRef_GetEps(VALUE self) {
1099 up = s_UnionParFromValue(self, &tp, 0);
1100 if (tp == kVdwParType) {
1104 } else if (tp == kVdwPairParType) {
1108 } else rb_raise(rb_eMolbyError, "invalid member eps");
1109 /* if (a == 0.0 || b == 0.0) */
1110 return rb_float_new(eps * INTERNAL2KCAL);
1111 /* else return rb_float_new(b*b/a/4.0 * INTERNAL2KCAL); */
1118 * Get the "A" value for the 1-4 van der Waals parameter.
1121 static VALUE s_ParameterRef_GetA14(VALUE self) {
1124 up = s_UnionParFromValue(self, &tp, 0);
1125 if (tp == kVdwParType)
1126 return rb_float_new(up->vdw.A14);
1127 else if (tp == kVdwPairParType)
1128 return rb_float_new(up->vdwp.A14);
1129 else rb_raise(rb_eMolbyError, "invalid member A14");
1137 * Get the "B" value for the 1-4 van der Waals parameter.
1140 static VALUE s_ParameterRef_GetB14(VALUE self) {
1143 up = s_UnionParFromValue(self, &tp, 0);
1144 if (tp == kVdwParType)
1145 return rb_float_new(up->vdw.B14);
1146 else if (tp == kVdwPairParType)
1147 return rb_float_new(up->vdwp.B14);
1148 else rb_raise(rb_eMolbyError, "invalid member B14");
1156 * Get the equilibrium radius (half of the minimum energy distance) for the 1-4 van der Waals parameter.
1158 static VALUE s_ParameterRef_GetReq14(VALUE self) {
1161 /* Double a, b, r; */
1163 up = s_UnionParFromValue(self, &tp, 0);
1164 if (tp == kVdwParType) {
1168 } else if (tp == kVdwPairParType) {
1169 /* a = up->vdwp.A14;
1170 b = up->vdwp.B14; */
1171 r = up->vdwp.r_eq14;
1172 } else rb_raise(rb_eMolbyError, "invalid member r_eq14");
1173 /* if (a == 0.0 || b == 0.0) */
1174 return rb_float_new(r);
1175 /* else return rb_float_new(pow(2*a/b, 1.0/6.0)); */
1182 * Get the minimum energy for the 1-4 van der Waals parameter.
1184 static VALUE s_ParameterRef_GetEps14(VALUE self) {
1189 up = s_UnionParFromValue(self, &tp, 0);
1190 if (tp == kVdwParType) {
1194 } else if (tp == kVdwPairParType) {
1195 /* a = up->vdwp.A14;
1196 b = up->vdwp.B14; */
1198 } else rb_raise(rb_eMolbyError, "invalid member eps14");
1199 /* if (a == 0.0 || b == 0.0) */
1200 return rb_float_new(eps * INTERNAL2KCAL);
1201 /* else return rb_float_new(b*b/a/4.0 * INTERNAL2KCAL); */
1208 * Get the cutoff distance for the van der Waals pair-specific cutoff parameter.
1210 static VALUE s_ParameterRef_GetCutoff(VALUE self) {
1213 up = s_UnionParFromValue(self, &tp, 0);
1214 if (tp == kVdwCutoffParType)
1215 return rb_float_new(up->vdwcutoff.cutoff);
1216 else rb_raise(rb_eMolbyError, "invalid member cutoff");
1223 * Get the atomic radius for the atom display parameter.
1225 static VALUE s_ParameterRef_GetRadius(VALUE self) {
1228 up = s_UnionParFromValue(self, &tp, 0);
1229 if (tp == kElementParType)
1230 return rb_float_new(up->atom.radius);
1231 else rb_raise(rb_eMolbyError, "invalid member radius");
1236 * color -> [Float, Float, Float]
1238 * Get the rgb color for the atom display parameter.
1240 static VALUE s_ParameterRef_GetColor(VALUE self) {
1243 up = s_UnionParFromValue(self, &tp, 0);
1244 if (tp == kElementParType)
1245 return rb_ary_new3(3, rb_float_new(up->atom.r), rb_float_new(up->atom.g), rb_float_new(up->atom.b));
1246 else rb_raise(rb_eMolbyError, "invalid member color");
1251 * atomic_number -> Integer
1253 * Get the atomic number for the vdw or atom parameter.
1255 static VALUE s_ParameterRef_GetAtomicNumber(VALUE self) {
1258 up = s_UnionParFromValue(self, &tp, 0);
1259 if (tp == kElementParType)
1260 return INT2NUM(up->atom.number);
1261 else if (tp == kVdwParType)
1262 return INT2NUM(up->vdw.atomicNumber);
1263 else rb_raise(rb_eMolbyError, "invalid member atomic_number");
1270 * Get the name for the atom display parameter.
1272 static VALUE s_ParameterRef_GetName(VALUE self) {
1275 up = s_UnionParFromValue(self, &tp, 0);
1276 if (tp == kElementParType) {
1278 strncpy(name, up->atom.name, 4);
1280 return rb_str_new2(name);
1281 } else rb_raise(rb_eMolbyError, "invalid member name");
1288 * Get the atomic weight for the atom display parameter.
1290 static VALUE s_ParameterRef_GetWeight(VALUE self) {
1293 up = s_UnionParFromValue(self, &tp, 0);
1294 if (tp == kElementParType)
1295 return rb_float_new(up->atom.weight);
1296 else if (tp == kVdwParType)
1297 return rb_float_new(up->vdw.weight);
1298 else rb_raise(rb_eMolbyError, "invalid member weight");
1303 * fullname -> String
1305 * Get the full name for the atom display parameter.
1307 static VALUE s_ParameterRef_GetFullName(VALUE self) {
1310 up = s_UnionParFromValue(self, &tp, 0);
1311 if (tp == kElementParType) {
1313 strncpy(fullname, up->atom.fullname, 15);
1315 return rb_str_new2(fullname);
1316 } else rb_raise(rb_eMolbyError, "invalid member fullname");
1323 * Get the comment for the parameter.
1325 static VALUE s_ParameterRef_GetComment(VALUE self) {
1328 up = s_UnionParFromValue(self, &tp, 0);
1332 else return rb_str_new2(ParameterGetComment(com));
1339 * Get the source string for the parameter. Returns false for undefined parameter,
1340 * and nil for "local" parameter that is specific for the molecule.
1342 static VALUE s_ParameterRef_GetSource(VALUE self) {
1345 up = s_UnionParFromValue(self, &tp, 0);
1348 return Qfalse; /* undefined */
1350 return Qnil; /* local */
1351 else return rb_str_new2(ParameterGetComment(src));
1355 s_ScanAtomTypes(VALUE val, Int n, UInt *types)
1362 if (rb_obj_is_kind_of(val, rb_cString)) {
1363 char *s = StringValuePtr(val);
1365 for (i = 0; i < n; i++) {
1368 /* Skip leading separaters */
1369 while (*s == '-' || *s == ' ' || *s == '\t')
1371 for (p = s; *p != 0; p++) {
1372 if (*p == '-' || *p == ' ' || *p == '\t')
1376 if (len >= sizeof(buf))
1377 len = sizeof(buf) - 1;
1378 strncpy(buf, s, len);
1380 /* Skip trailing blanks */
1381 while (--len >= 0 && (buf[len] == ' ' || buf[len] == '\t'))
1384 rb_raise(rb_eMolbyError, "Bad atom type specification: %s", StringValuePtr(val));
1385 if (buf[0] >= '0' && buf[0] <= '9')
1386 types[i] = atoi(buf);
1388 types[i] = AtomTypeEncodeToUInt(buf);
1389 if (p == NULL || *p == 0) {
1395 rb_raise(rb_eMolbyError, "%d atom types are required but only %d are given; %s", n, i, StringValuePtr(val));
1398 val = rb_ary_to_ary(val);
1399 if (RARRAY_LEN(val) != n)
1400 rb_raise(rb_eMolbyError, "an array of %d atom types is required", n);
1401 valp = RARRAY_PTR(val);
1403 for (i = 0; i < n; i++) {
1404 if (rb_obj_is_kind_of(valp[i], rb_cNumeric))
1405 types[i] = NUM2INT(rb_Integer(valp[i]));
1407 VALUE sval = valp[i];
1408 types[i] = AtomTypeEncodeToUInt(StringValuePtr(sval));
1413 static VALUE s_ParameterRef_SetAtomTypes(VALUE self, VALUE val) {
1418 up = s_UnionParFromValue(self, &tp, 1);
1419 oldval = s_ParameterRef_GetAtomTypes(self);
1420 oldsrc = up->bond.src;
1423 s_ScanAtomTypes(val, 2, types);
1424 up->bond.type1 = types[0];
1425 up->bond.type2 = types[1];
1428 s_ScanAtomTypes(val, 3, types);
1429 up->angle.type1 = types[0];
1430 up->angle.type2 = types[1];
1431 up->angle.type3 = types[2];
1433 case kDihedralParType:
1434 case kImproperParType:
1435 s_ScanAtomTypes(val, 4, types);
1436 up->torsion.type1 = types[0];
1437 up->torsion.type2 = types[1];
1438 up->torsion.type3 = types[2];
1439 up->torsion.type4 = types[3];
1442 s_ScanAtomTypes(val, 1, types);
1443 up->vdw.type1 = types[0];
1445 case kVdwPairParType:
1446 s_ScanAtomTypes(val, 2, types);
1447 up->vdwp.type1 = types[0];
1448 up->vdwp.type2 = types[1];
1450 case kVdwCutoffParType:
1451 s_ScanAtomTypes(val, 2, types);
1452 up->vdwcutoff.type1 = types[0];
1453 up->vdwcutoff.type2 = types[1];
1458 s_RegisterUndoForParameterAttrChange(self, s_AtomTypesSym, val, oldval, oldsrc);
1462 static VALUE s_ParameterRef_SetK(VALUE self, VALUE val) {
1464 Int tp, i, n, oldsrc;
1465 VALUE *valp, oldval;
1466 up = s_UnionParFromValue(self, &tp, 1);
1467 oldval = s_ParameterRef_GetK(self);
1468 oldsrc = up->bond.src;
1471 val = rb_Float(val);
1472 up->bond.k = NUM2DBL(val) * KCAL2INTERNAL;
1475 val = rb_Float(val);
1476 up->angle.k = NUM2DBL(val) * KCAL2INTERNAL;
1478 case kDihedralParType:
1479 case kImproperParType:
1480 if (up->torsion.mult == 1 || up->torsion.mult == 0) {
1481 up->torsion.mult = 1;
1482 val = rb_Float(val);
1483 up->torsion.k[0] = NUM2DBL(val) * KCAL2INTERNAL;
1486 n = up->torsion.mult;
1489 val = rb_ary_to_ary(val);
1490 if (RARRAY_LEN(val) != n)
1491 rb_raise(rb_eMolbyError, "the value should be an array of %d floats", n);
1492 valp = RARRAY_PTR(val);
1493 for (i = 0; i < n; i++) {
1494 up->torsion.k[i] = NUM2DBL(rb_Float(valp[i])) * KCAL2INTERNAL;
1498 rb_raise(rb_eMolbyError, "invalid member k");
1500 s_RegisterUndoForParameterAttrChange(self, s_KSym, val, oldval, oldsrc);
1504 static VALUE s_ParameterRef_SetR0(VALUE self, VALUE val) {
1508 up = s_UnionParFromValue(self, &tp, 1);
1509 oldval = s_ParameterRef_GetR0(self);
1510 oldsrc = up->bond.src;
1511 if (tp == kBondParType) {
1512 val = rb_Float(val);
1513 up->bond.r0 = NUM2DBL(val);
1514 } else rb_raise(rb_eMolbyError, "invalid member r0");
1515 s_RegisterUndoForParameterAttrChange(self, s_R0Sym, val, oldval, oldsrc);
1519 static VALUE s_ParameterRef_SetA0(VALUE self, VALUE val) {
1523 up = s_UnionParFromValue(self, &tp, 1);
1524 oldval = s_ParameterRef_GetA0(self);
1525 oldsrc = up->bond.src;
1526 if (tp == kAngleParType) {
1527 val = rb_Float(val);
1528 up->angle.a0 = NUM2DBL(val) * kDeg2Rad;
1529 } else rb_raise(rb_eMolbyError, "invalid member a0");
1530 s_RegisterUndoForParameterAttrChange(self, s_A0Sym, val, oldval, oldsrc);
1534 static VALUE s_ParameterRef_SetMult(VALUE self, VALUE val) {
1538 up = s_UnionParFromValue(self, &tp, 1);
1539 oldval = s_ParameterRef_GetMult(self);
1540 oldsrc = up->bond.src;
1541 if (tp == kDihedralParType || tp == kImproperParType) {
1543 val = rb_Integer(val);
1546 rb_raise(rb_eMolbyError, "torsion multiplicity should be 0..3");
1547 up->torsion.mult = i;
1548 } else rb_raise(rb_eMolbyError, "invalid member mult");
1549 s_RegisterUndoForParameterAttrChange(self, s_MultSym, val, oldval, oldsrc);
1553 static VALUE s_ParameterRef_SetPeriod(VALUE self, VALUE val) {
1555 Int tp, i, n, oldsrc;
1556 VALUE *valp, oldval;
1557 up = s_UnionParFromValue(self, &tp, 1);
1558 oldval = s_ParameterRef_GetPeriod(self);
1559 oldsrc = up->bond.src;
1560 if (tp == kDihedralParType || tp == kImproperParType) {
1561 if (up->torsion.mult == 1 || up->torsion.mult == 0) {
1562 up->torsion.mult = 1;
1563 val = rb_Integer(val);
1564 up->torsion.period[0] = NUM2INT(val);
1566 n = up->torsion.mult;
1569 val = rb_ary_to_ary(val);
1570 if (RARRAY_LEN(val) != n)
1571 rb_raise(rb_eMolbyError, "the value should be an array of %d integers", n);
1572 valp = RARRAY_PTR(val);
1573 for (i = 0; i < n; i++) {
1574 up->torsion.period[i] = NUM2INT(rb_Integer(valp[i]));
1577 } else rb_raise(rb_eMolbyError, "invalid member period");
1578 s_RegisterUndoForParameterAttrChange(self, s_PeriodSym, val, oldval, oldsrc);
1582 static VALUE s_ParameterRef_SetPhi0(VALUE self, VALUE val) {
1584 Int tp, i, n, oldsrc;
1585 VALUE *valp, oldval;
1586 up = s_UnionParFromValue(self, &tp, 1);
1587 oldval = s_ParameterRef_GetPhi0(self);
1588 oldsrc = up->bond.src;
1589 if (tp == kDihedralParType || tp == kImproperParType) {
1590 if (up->torsion.mult == 1 || up->torsion.mult == 0) {
1591 up->torsion.mult = 1;
1592 val = rb_Float(val);
1593 up->torsion.phi0[0] = NUM2DBL(val) * kDeg2Rad;
1595 n = up->torsion.mult;
1598 val = rb_ary_to_ary(val);
1599 if (RARRAY_LEN(val) != n)
1600 rb_raise(rb_eMolbyError, "the value should be an array of %d floats", n);
1601 valp = RARRAY_PTR(val);
1602 for (i = 0; i < n; i++)
1603 up->torsion.phi0[i] = NUM2DBL(rb_Float(valp[i])) * kDeg2Rad;
1605 } else rb_raise(rb_eMolbyError, "invalid member phi0");
1606 s_RegisterUndoForParameterAttrChange(self, s_Phi0Sym, val, oldval, oldsrc);
1611 static VALUE s_ParameterRef_SetA(VALUE self, VALUE val) {
1616 up = s_UnionParFromValue(self, &tp, 1);
1617 oldval = s_ParameterRef_GetA(self);
1618 oldsrc = up->bond.src;
1619 val = rb_Float(val);
1621 if (tp == kVdwParType)
1623 else if (tp == kVdwPairParType)
1625 else rb_raise(rb_eMolbyError, "invalid member A");
1626 s_RegisterUndoForParameterAttrChange(self, s_ASym, val, oldval, oldsrc);
1630 static VALUE s_ParameterRef_SetB(VALUE self, VALUE val) {
1635 up = s_UnionParFromValue(self, &tp, 1);
1636 oldval = s_ParameterRef_GetB(self);
1637 oldsrc = up->bond.src;
1638 val = rb_Float(val);
1640 if (tp == kVdwParType)
1642 else if (tp == kVdwPairParType)
1644 else rb_raise(rb_eMolbyError, "invalid member B");
1645 s_RegisterUndoForParameterAttrChange(self, s_BSym, val, oldval, oldsrc);
1650 static VALUE s_ParameterRef_SetReq(VALUE self, VALUE val) {
1655 up = s_UnionParFromValue(self, &tp, 1);
1656 oldval = s_ParameterRef_GetReq(self);
1657 oldsrc = up->bond.src;
1658 val = rb_Float(val);
1660 if (tp == kVdwParType) {
1662 up->vdw.A = pow(r * 2, 12.0) * up->vdw.eps;
1663 up->vdw.B = 2 * pow(r * 2, 6.0) * up->vdw.eps;
1664 } else if (tp == kVdwPairParType) {
1666 up->vdwp.A = pow(r * 2, 12.0) * up->vdwp.eps;
1667 up->vdwp.B = 2 * pow(r * 2, 6.0) * up->vdwp.eps;
1668 } else rb_raise(rb_eMolbyError, "invalid member r_eq");
1669 s_RegisterUndoForParameterAttrChange(self, s_ReqSym, val, oldval, oldsrc);
1673 static VALUE s_ParameterRef_SetEps(VALUE self, VALUE val) {
1678 up = s_UnionParFromValue(self, &tp, 1);
1679 oldval = s_ParameterRef_GetEps(self);
1680 oldsrc = up->bond.src;
1681 val = rb_Float(val);
1682 e = NUM2DBL(val) * KCAL2INTERNAL;
1683 if (tp == kVdwParType) {
1685 up->vdw.A = pow(up->vdw.r_eq * 2, 12.0) * up->vdw.eps;
1686 up->vdw.B = 2 * pow(up->vdw.r_eq * 2, 6.0) * up->vdw.eps;
1687 } else if (tp == kVdwPairParType) {
1689 up->vdwp.A = pow(up->vdwp.r_eq * 2, 12.0) * up->vdwp.eps;
1690 up->vdwp.B = 2 * pow(up->vdwp.r_eq * 2, 6.0) * up->vdwp.eps;
1691 } else rb_raise(rb_eMolbyError, "invalid member eps");
1692 s_RegisterUndoForParameterAttrChange(self, s_EpsSym, val, oldval, oldsrc);
1697 static VALUE s_ParameterRef_SetA14(VALUE self, VALUE val) {
1702 up = s_UnionParFromValue(self, &tp, 1);
1703 oldval = s_ParameterRef_GetA14(self);
1704 oldsrc = up->bond.src;
1705 val = rb_Float(val);
1707 if (tp == kVdwParType)
1709 else if (tp == kVdwPairParType)
1711 else rb_raise(rb_eMolbyError, "invalid member A14");
1712 s_RegisterUndoForParameterAttrChange(self, s_A14Sym, val, oldval, oldsrc);
1716 static VALUE s_ParameterRef_SetB14(VALUE self, VALUE val) {
1721 up = s_UnionParFromValue(self, &tp, 1);
1722 oldval = s_ParameterRef_GetB14(self);
1723 oldsrc = up->bond.src;
1724 val = rb_Float(val);
1726 if (tp == kVdwParType)
1728 else if (tp == kVdwPairParType)
1730 else rb_raise(rb_eMolbyError, "invalid member B14");
1731 s_RegisterUndoForParameterAttrChange(self, s_B14Sym, val, oldval, oldsrc);
1736 static VALUE s_ParameterRef_SetReq14(VALUE self, VALUE val) {
1741 up = s_UnionParFromValue(self, &tp, 1);
1742 oldval = s_ParameterRef_GetReq14(self);
1743 oldsrc = up->bond.src;
1744 val = rb_Float(val);
1746 if (tp == kVdwParType) {
1748 up->vdw.A14 = pow(up->vdw.r_eq14 * 2, 12.0) * up->vdw.eps14;
1749 up->vdw.B14 = 2 * pow(up->vdw.r_eq14 * 2, 6.0) * up->vdw.eps14;
1750 } else if (tp == kVdwPairParType) {
1751 up->vdwp.r_eq14 = r;
1752 up->vdwp.A14 = pow(up->vdwp.r_eq14 * 2, 12.0) * up->vdwp.eps14;
1753 up->vdwp.B14 = 2 * pow(up->vdwp.r_eq14 * 2, 6.0) * up->vdwp.eps14;
1754 } else rb_raise(rb_eMolbyError, "invalid member r_eq14");
1755 s_RegisterUndoForParameterAttrChange(self, s_Req14Sym, val, oldval, oldsrc);
1759 static VALUE s_ParameterRef_SetEps14(VALUE self, VALUE val) {
1764 up = s_UnionParFromValue(self, &tp, 1);
1765 oldval = s_ParameterRef_GetEps14(self);
1766 oldsrc = up->bond.src;
1767 val = rb_Float(val);
1768 e = NUM2DBL(val) * KCAL2INTERNAL;
1769 if (tp == kVdwParType) {
1771 up->vdw.A14 = pow(up->vdw.r_eq14 * 2, 12.0) * up->vdw.eps14;
1772 up->vdw.B14 = 2 * pow(up->vdw.r_eq14 * 2, 6.0) * up->vdw.eps14;
1773 } else if (tp == kVdwPairParType) {
1775 up->vdwp.A14 = pow(up->vdwp.r_eq14 * 2, 12.0) * up->vdwp.eps14;
1776 up->vdwp.B14 = 2 * pow(up->vdwp.r_eq14 * 2, 6.0) * up->vdwp.eps14;
1777 } else rb_raise(rb_eMolbyError, "invalid member eps14");
1778 s_RegisterUndoForParameterAttrChange(self, s_Eps14Sym, val, oldval, oldsrc);
1782 static VALUE s_ParameterRef_SetCutoff(VALUE self, VALUE val) {
1786 oldval = s_ParameterRef_GetCutoff(self);
1787 oldsrc = up->bond.src;
1788 up = s_UnionParFromValue(self, &tp, 1);
1789 val = rb_Float(val);
1790 if (tp == kVdwCutoffParType) {
1791 up->vdwcutoff.cutoff = NUM2DBL(val);
1792 } else rb_raise(rb_eMolbyError, "invalid member cutoff");
1793 s_RegisterUndoForParameterAttrChange(self, s_CutoffSym, val, oldval, oldsrc);
1797 static VALUE s_ParameterRef_SetRadius(VALUE self, VALUE val) {
1801 up = s_UnionParFromValue(self, &tp, 1);
1802 oldval = s_ParameterRef_GetRadius(self);
1803 oldsrc = up->bond.src;
1804 val = rb_Float(val);
1805 if (tp == kElementParType) {
1806 up->atom.radius = NUM2DBL(val);
1807 } else rb_raise(rb_eMolbyError, "invalid member radius");
1808 s_RegisterUndoForParameterAttrChange(self, s_RadiusSym, val, oldval, oldsrc);
1812 static VALUE s_ParameterRef_SetColor(VALUE self, VALUE val) {
1815 VALUE *valp, oldval;
1816 up = s_UnionParFromValue(self, &tp, 1);
1817 oldval = s_ParameterRef_GetColor(self);
1818 oldsrc = up->bond.src;
1819 val = rb_ary_to_ary(val);
1820 if (RARRAY_LEN(val) != 3)
1821 rb_raise(rb_eMolbyError, "value should be an array of three floats (r, g, b)");
1822 valp = RARRAY_PTR(val);
1823 if (tp == kElementParType) {
1824 up->atom.r = NUM2DBL(rb_Float(valp[0]));
1825 up->atom.g = NUM2DBL(rb_Float(valp[1]));
1826 up->atom.b = NUM2DBL(rb_Float(valp[2]));
1827 } else rb_raise(rb_eMolbyError, "invalid member color");
1828 s_RegisterUndoForParameterAttrChange(self, s_ColorSym, val, oldval, oldsrc);
1832 static VALUE s_ParameterRef_SetAtomicNumber(VALUE self, VALUE val) {
1836 up = s_UnionParFromValue(self, &tp, 1);
1837 oldval = s_ParameterRef_GetAtomicNumber(self);
1838 oldsrc = up->bond.src;
1839 val = rb_Integer(val);
1840 if (tp == kElementParType)
1841 up->atom.number = NUM2INT(val);
1842 else if (tp == kVdwParType) {
1843 up->vdw.atomicNumber = NUM2INT(val);
1844 up->vdw.weight = WeightForAtomicNumber(up->vdw.atomicNumber);
1845 } else rb_raise(rb_eMolbyError, "invalid member atomic_number");
1846 s_RegisterUndoForParameterAttrChange(self, s_AtomicNumberSym, val, oldval, oldsrc);
1850 static VALUE s_ParameterRef_SetName(VALUE self, VALUE val) {
1854 up = s_UnionParFromValue(self, &tp, 1);
1855 oldval = s_ParameterRef_GetName(self);
1856 oldsrc = up->bond.src;
1857 if (tp == kElementParType) {
1858 strncpy(up->atom.name, StringValuePtr(val), 4);
1859 } else rb_raise(rb_eMolbyError, "invalid member name");
1860 s_RegisterUndoForParameterAttrChange(self, s_NameSym, val, oldval, oldsrc);
1864 static VALUE s_ParameterRef_SetWeight(VALUE self, VALUE val) {
1868 val = rb_Float(val);
1869 oldval = s_ParameterRef_GetWeight(self);
1870 up = s_UnionParFromValue(self, &tp, 1);
1871 oldsrc = up->bond.src;
1872 if (tp == kElementParType)
1873 up->atom.weight = NUM2DBL(val);
1874 else if (tp == kVdwParType)
1875 up->vdw.weight = NUM2DBL(val);
1876 else rb_raise(rb_eMolbyError, "invalid member weight");
1877 s_RegisterUndoForParameterAttrChange(self, s_WeightSym, val, oldval, oldsrc);
1881 static VALUE s_ParameterRef_SetFullName(VALUE self, VALUE val) {
1885 up = s_UnionParFromValue(self, &tp, 1);
1886 oldval = s_ParameterRef_GetFullName(self);
1887 oldsrc = up->bond.src;
1888 if (tp == kElementParType) {
1889 strncpy(up->atom.fullname, StringValuePtr(val), 15);
1890 up->atom.fullname[15] = 0;
1891 } else rb_raise(rb_eMolbyError, "invalid member fullname");
1892 s_RegisterUndoForParameterAttrChange(self, s_FullNameSym, val, oldval, oldsrc);
1896 static VALUE s_ParameterRef_SetComment(VALUE self, VALUE val) {
1898 Int tp, com, oldsrc;
1900 up = s_UnionParFromValue(self, &tp, 1);
1901 oldval = s_ParameterRef_GetComment(self);
1902 oldsrc = up->bond.src;
1906 com = ParameterCommentIndex(StringValuePtr(val));
1909 s_RegisterUndoForParameterAttrChange(self, s_CommentSym, val, oldval, oldsrc);
1913 /* Only false (undefined) and nil (local) can be set */
1914 static VALUE s_ParameterRef_SetSource(VALUE self, VALUE val) {
1918 up = s_UnionParFromValue(self, &tp, 1);
1919 if (val != Qfalse && val != Qnil)
1920 rb_raise(rb_eMolbyError, "set source: only false (undefined parameter) or nil (local parameter) is allowed");
1921 oldval = s_ParameterRef_GetSource(self);
1922 oldsrc = up->bond.src;
1923 if (oldsrc != 0 && oldsrc != -1)
1924 rb_raise(rb_eMolbyError, "source information of global parameter cannot be modified");
1925 up->bond.src = (val == Qfalse ? -1 : 0);
1926 s_RegisterUndoForParameterAttrChange(self, s_SourceSym, val, oldval, oldsrc);
1930 static struct s_ParameterAttrDef {
1932 VALUE *symref; /* Address of s_IndexSymbol etc. */
1933 ID id; /* Will be set within InitMolby() */
1934 VALUE (*getter)(VALUE);
1935 VALUE (*setter)(VALUE, VALUE);
1936 } s_ParameterAttrDefTable[] = {
1937 {"index", &s_IndexSym, 0, s_ParameterRef_GetIndex, NULL},
1938 {"par_type", &s_ParTypeSym, 0, s_ParameterRef_GetParType, NULL},
1939 {"atom_types", &s_AtomTypesSym, 0, s_ParameterRef_GetAtomTypes, s_ParameterRef_SetAtomTypes},
1940 {"atom_type", &s_AtomTypeSym, 0, s_ParameterRef_GetAtomTypes, s_ParameterRef_SetAtomTypes},
1941 {"k", &s_KSym, 0, s_ParameterRef_GetK, s_ParameterRef_SetK},
1942 {"r0", &s_R0Sym, 0, s_ParameterRef_GetR0, s_ParameterRef_SetR0},
1943 {"a0", &s_A0Sym, 0, s_ParameterRef_GetA0, s_ParameterRef_SetA0},
1944 {"mult", &s_MultSym, 0, s_ParameterRef_GetMult, s_ParameterRef_SetMult},
1945 {"period", &s_PeriodSym, 0, s_ParameterRef_GetPeriod, s_ParameterRef_SetPeriod},
1946 {"phi0", &s_Phi0Sym, 0, s_ParameterRef_GetPhi0, s_ParameterRef_SetPhi0},
1947 /* {"A", &s_ASym, 0, s_ParameterRef_GetA, NULL},
1948 {"B", &s_BSym, 0, s_ParameterRef_GetB, NULL}, */
1949 {"r_eq", &s_ReqSym, 0, s_ParameterRef_GetReq, s_ParameterRef_SetReq},
1950 {"eps", &s_EpsSym, 0, s_ParameterRef_GetEps, s_ParameterRef_SetEps},
1951 /* {"A14", &s_A14Sym, 0, s_ParameterRef_GetA14, NULL},
1952 {"B14", &s_B14Sym, 0, s_ParameterRef_GetB14, NULL}, */
1953 {"r_eq14", &s_Req14Sym, 0, s_ParameterRef_GetReq14, s_ParameterRef_SetReq14},
1954 {"eps14", &s_Eps14Sym, 0, s_ParameterRef_GetEps14, s_ParameterRef_SetEps14},
1955 {"cutoff", &s_CutoffSym, 0, s_ParameterRef_GetCutoff, s_ParameterRef_SetCutoff},
1956 {"radius", &s_RadiusSym, 0, s_ParameterRef_GetRadius, s_ParameterRef_SetRadius},
1957 {"color", &s_ColorSym, 0, s_ParameterRef_GetColor, s_ParameterRef_SetColor},
1958 {"atomic_number",&s_AtomicNumberSym, 0, s_ParameterRef_GetAtomicNumber, s_ParameterRef_SetAtomicNumber},
1959 {"name", &s_NameSym, 0, s_ParameterRef_GetName, s_ParameterRef_SetName},
1960 {"weight", &s_WeightSym, 0, s_ParameterRef_GetWeight, s_ParameterRef_SetWeight},
1961 {"fullname", &s_FullNameSym, 0, s_ParameterRef_GetFullName, s_ParameterRef_SetFullName},
1962 {"comment", &s_CommentSym, 0, s_ParameterRef_GetComment, s_ParameterRef_SetComment},
1963 {"source", &s_SourceSym, 0, s_ParameterRef_GetSource, s_ParameterRef_SetSource},
1964 {NULL} /* Sentinel */
1968 s_ParameterRef_SetAttr(VALUE self, VALUE key, VALUE value)
1972 if (TYPE(key) != T_SYMBOL) {
1973 kid = rb_intern(StringValuePtr(key));
1975 } else kid = SYM2ID(key);
1976 for (i = 0; s_ParameterAttrDefTable[i].name != NULL; i++) {
1977 if (s_ParameterAttrDefTable[i].id == kid) {
1978 if (value == Qundef)
1979 return (*(s_ParameterAttrDefTable[i].getter))(self);
1981 return (*(s_ParameterAttrDefTable[i].setter))(self, value);
1984 rb_raise(rb_eMolbyError, "unknown parameter attribute \"%s\"", rb_id2name(kid));
1985 return Qnil; /* not reached */
1989 s_ParameterRef_GetAttr(VALUE self, VALUE key)
1991 return s_ParameterRef_SetAttr(self, key, Qundef);
1996 * keys(idx) -> array of valid parameter attributes
1998 * Returns an array of valid parameter attributes (as Symbols).
2001 s_ParameterRef_Keys(VALUE self)
2004 Data_Get_Struct(self, ParameterRef, pref);
2005 switch (pref->parType) {
2007 return rb_ary_new3(7, s_IndexSym, s_ParTypeSym, s_AtomTypesSym, s_KSym, s_R0Sym, s_CommentSym, s_SourceSym);
2009 return rb_ary_new3(7, s_IndexSym, s_ParTypeSym, s_AtomTypesSym, s_KSym, s_A0Sym, s_CommentSym, s_SourceSym);
2010 case kDihedralParType:
2011 case kImproperParType:
2012 return rb_ary_new3(9, s_IndexSym, s_ParTypeSym, s_AtomTypesSym, s_MultSym, s_KSym, s_PeriodSym, s_Phi0Sym, s_CommentSym, s_SourceSym);
2014 return rb_ary_new3(11, s_IndexSym, s_ParTypeSym, s_AtomTypesSym, s_AtomicNumberSym, s_ReqSym, s_EpsSym, s_Req14Sym, s_Eps14Sym, s_WeightSym, s_CommentSym, s_SourceSym);
2015 case kVdwPairParType:
2016 return rb_ary_new3(9, s_IndexSym, s_ParTypeSym, s_AtomTypesSym, s_ReqSym, s_EpsSym, s_Req14Sym, s_Eps14Sym, s_CommentSym, s_SourceSym);
2017 case kVdwCutoffParType:
2018 return rb_ary_new3(6, s_IndexSym, s_ParTypeSym, s_AtomTypesSym, s_CutoffSym, s_CommentSym, s_SourceSym);
2019 case kElementParType:
2020 return rb_ary_new3(10, s_IndexSym, s_ParTypeSym, s_AtomicNumberSym, s_NameSym, s_FullNameSym, s_RadiusSym, s_ColorSym, s_WeightSym, s_CommentSym, s_SourceSym);
2022 rb_raise(rb_eMolbyError, "internal error: invalid parameter type");
2024 return Qnil; /* Not reached */
2029 * to_hash(idx) -> Hash
2031 * Returns a hash containing valid parameter names and values
2034 s_ParameterRef_ToHash(VALUE self)
2036 VALUE keys = s_ParameterRef_Keys(self);
2041 retval = rb_hash_new();
2042 for (i = 0; i < RARRAY_LEN(keys); i++) {
2043 VALUE key = RARRAY_PTR(keys)[i];
2044 VALUE val = s_ParameterRef_GetAttr(self, key);
2045 rb_hash_aset(retval, key, val);
2052 * parameter.to_s(idx) -> String
2054 * Returns a string representation of the given parameter
2057 s_ParameterRef_ToString(VALUE self)
2060 char buf[1024], types[4][8];
2061 UnionPar *up = s_UnionParFromValue(self, &tp, 0);
2064 snprintf(buf, sizeof buf, "bond %4.6s %4.6s %8.2f %8.3f", AtomTypeDecodeToString(up->bond.type1, types[0]), AtomTypeDecodeToString(up->bond.type2, types[1]), up->bond.k * INTERNAL2KCAL, up->bond.r0);
2067 snprintf(buf, sizeof buf, "angle %4.6s %4.6s %4.6s %8.2f %8.3f", AtomTypeDecodeToString(up->angle.type1, types[0]), AtomTypeDecodeToString(up->angle.type2, types[1]), AtomTypeDecodeToString(up->angle.type3, types[2]), up->angle.k * INTERNAL2KCAL, up->angle.a0 * kRad2Deg);
2069 case kDihedralParType:
2070 case kImproperParType:
2071 snprintf(buf, sizeof buf, "%s %4.6s %4.6s %4.6s %4.6s", (tp == kDihedralParType ? "dihe" : "impr"), AtomTypeDecodeToString(up->torsion.type1, types[0]), AtomTypeDecodeToString(up->torsion.type2, types[1]), AtomTypeDecodeToString(up->torsion.type3, types[2]), AtomTypeDecodeToString(up->torsion.type4, types[3]));
2073 for (i = 0; i < up->torsion.mult; i++) {
2074 snprintf(buf + n, sizeof buf - n, " %8.2f %2d %8.3f", up->torsion.k[i] * INTERNAL2KCAL, up->torsion.period[i], up->torsion.phi0[i] * kRad2Deg);
2079 snprintf(buf, sizeof buf, "nonbonded %4.6s %8.4f %8.4f %8.4f %8.4f", AtomTypeDecodeToString(up->vdw.type1, types[0]), up->vdw.A * INTERNAL2KCAL / pow(up->vdw.r_eq, 12.0), up->vdw.r_eq / 1.12246204830937, up->vdw.A14 * INTERNAL2KCAL / pow(up->vdw.r_eq14, 12.0), up->vdw.r_eq14 / 1.12246204830937);
2081 case kVdwPairParType:
2082 snprintf(buf, sizeof buf, "nbfi %4.6s %4.6s %12.8e %12.8e %12.8e %12.8e", AtomTypeDecodeToString(up->vdwp.type1, types[0]), AtomTypeDecodeToString(up->vdwp.type2, types[1]), up->vdwp.A * INTERNAL2KCAL, up->vdwp.B * INTERNAL2KCAL, up->vdwp.A14 * INTERNAL2KCAL, up->vdwp.B14 * INTERNAL2KCAL);
2084 case kVdwCutoffParType:
2085 snprintf(buf, sizeof buf, "vdwcutoff %4.6s %4.6s %8.4f", AtomTypeDecodeToString(up->vdwcutoff.type1, types[0]), AtomTypeDecodeToString(up->vdwcutoff.type2, types[1]), up->vdwcutoff.cutoff);
2087 case kElementParType:
2088 snprintf(buf, sizeof buf, "element %2.2s %3d %6.3f %6.3f %6.3f %6.3f %8.4f %s", up->atom.name, up->atom.number, up->atom.radius, up->atom.r, up->atom.g, up->atom.b, up->atom.weight, up->atom.fullname);
2091 return rb_str_new2(buf);
2096 * self == parameterRef -> boolean
2098 * True if the parameters point to the same parameter record.
2101 s_ParameterRef_Equal(VALUE self, VALUE val)
2104 if (rb_obj_is_kind_of(val, rb_cParameterRef)) {
2105 return (s_UnionParFromValue(self, &tp1, 0) == s_UnionParFromValue(val, &tp2, 0) ? Qtrue : Qfalse);
2106 } else return Qfalse;
2109 #pragma mark ====== Parameter Class ======
2111 /* The Parameter class actually encapsulate Molecule record. If the record pointer
2112 * is NULL, then the global parameters are looked for. */
2114 /* Rebuild the MD parameter record if necessary: may throw an exception */
2115 /* The second parameter is passed to md_arena.prepare; if true, then check only */
2117 s_RebuildMDParameterIfNecessary(VALUE val, VALUE cval)
2120 Data_Get_Struct(val, Molecule, mol);
2122 rb_raise(rb_eMolbyError, "the molecule is empty");
2123 if (mol->par == NULL || mol->arena == NULL || mol->arena->is_initialized == 0 || mol->needsMDRebuild) {
2124 /* Do self.md_arena.prepare */
2125 VALUE val2 = rb_funcall(val, rb_intern("md_arena"), 0);
2127 val2 = rb_funcall(val2, rb_intern("prepare"), 1, cval);
2132 s_NewParameterValueFromValue(VALUE val)
2135 if (rb_obj_is_kind_of(val, rb_cMolecule)) {
2136 Data_Get_Struct(val, Molecule, mol);
2137 s_RebuildMDParameterIfNecessary(val, Qtrue);
2138 MoleculeRetain(mol);
2139 return Data_Wrap_Struct(rb_cParameter, 0, (void (*)(void *))MoleculeRelease, mol);
2142 return Data_Wrap_Struct(rb_cParameter, 0, NULL, mol);
2147 s_MoleculeFromParameterValue(VALUE val)
2150 Data_Get_Struct(val, Molecule, mol);
2155 s_ParameterFromParameterValue(VALUE val)
2158 Data_Get_Struct(val, Molecule, mol);
2161 return gBuiltinParameters;
2164 /* Forward declarations */
2165 static VALUE s_NewParEnumerableValueFromMoleculeAndType(Molecule *mol, Int parType);
2166 static Molecule *s_MoleculeFromParEnumerableValue(VALUE val);
2169 s_MoleculeFromParameterOrParEnumerableValue(VALUE val)
2171 if (val == rb_cParameter) {
2172 return NULL; /* Parameter class method: builtin parameters */
2173 } else if (rb_obj_is_kind_of(val, rb_cParameter)) {
2174 return s_MoleculeFromParameterValue(val);
2175 } else if (rb_obj_is_kind_of(val, rb_cParEnumerable)) {
2176 return s_MoleculeFromParEnumerableValue(val);
2182 * builtin -> Parameter
2184 * Returns a parameter value that points to the global (builtin) parameters.
2185 * Equivalent to Parameter::Builtin (constant).
2188 s_Parameter_Builtin(VALUE self)
2190 static ID s_builtin_id = 0;
2191 if (s_builtin_id == 0)
2192 s_builtin_id = rb_intern("Builtin");
2193 return rb_const_get(rb_cParameter, s_builtin_id);
2198 * bond(idx) -> ParameterRef
2200 * The index-th bond parameter record is returned.
2203 s_Parameter_Bond(VALUE self, VALUE ival)
2207 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2208 idx = NUM2INT(rb_Integer(ival));
2210 n = gBuiltinParameters->nbondPars;
2211 else if (mol->par != NULL)
2212 n = mol->par->nbondPars;
2214 if (idx < -n || idx >= n)
2215 rb_raise(rb_eMolbyError, "Bond parameter index (%d) out of range", idx);
2218 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kBondParType, idx);
2223 * angle(idx) -> ParameterRef
2225 * The index-th angle parameter record is returned.
2228 s_Parameter_Angle(VALUE self, VALUE ival)
2232 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2233 idx = NUM2INT(rb_Integer(ival));
2235 n = gBuiltinParameters->nanglePars;
2236 else if (mol->par != NULL)
2237 n = mol->par->nanglePars;
2239 if (idx < -n || idx >= n)
2240 rb_raise(rb_eMolbyError, "Angle parameter index (%d) out of range", idx);
2243 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kAngleParType, idx);
2248 * dihedral(idx) -> ParameterRef
2250 * The index-th dihedral parameter record is returned.
2253 s_Parameter_Dihedral(VALUE self, VALUE ival)
2257 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2258 idx = NUM2INT(rb_Integer(ival));
2260 n = gBuiltinParameters->ndihedralPars;
2261 else if (mol->par != NULL)
2262 n = mol->par->ndihedralPars;
2264 if (idx < -n || idx >= n)
2265 rb_raise(rb_eMolbyError, "Dihedral parameter index (%d) out of range", idx);
2268 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kDihedralParType, idx);
2273 * improper(idx) -> ParameterRef
2275 * The index-th improper parameter record is returned.
2278 s_Parameter_Improper(VALUE self, VALUE ival)
2282 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2283 idx = NUM2INT(rb_Integer(ival));
2285 n = gBuiltinParameters->nimproperPars;
2286 else if (mol->par != NULL)
2287 n = mol->par->nimproperPars;
2289 if (idx < -n || idx >= n)
2290 rb_raise(rb_eMolbyError, "Improper parameter index (%d) out of range", idx);
2293 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kImproperParType, idx);
2298 * vdw(idx) -> ParameterRef
2300 * The index-th vdw parameter record is returned.
2303 s_Parameter_Vdw(VALUE self, VALUE ival)
2307 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2308 idx = NUM2INT(rb_Integer(ival));
2310 n = gBuiltinParameters->nvdwPars;
2311 else if (mol->par != NULL)
2312 n = mol->par->nvdwPars;
2314 if (idx < -n || idx >= n)
2315 rb_raise(rb_eMolbyError, "Vdw parameter index (%d) out of range", idx);
2318 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwParType, idx);
2323 * vdw_pair(idx) -> ParameterRef
2325 * The index-th vdw pair parameter record is returned.
2328 s_Parameter_VdwPair(VALUE self, VALUE ival)
2332 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2333 idx = NUM2INT(rb_Integer(ival));
2335 n = gBuiltinParameters->nvdwpPars;
2336 else if (mol->par != NULL)
2337 n = mol->par->nvdwpPars;
2339 if (idx < -n || idx >= n)
2340 rb_raise(rb_eMolbyError, "Vdw pair parameter index (%d) out of range", idx);
2343 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwPairParType, idx);
2348 * vdw_cutoff(idx) -> ParameterRef
2350 * The index-th vdw cutoff parameter record is returned.
2353 s_Parameter_VdwCutoff(VALUE self, VALUE ival)
2357 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2358 idx = NUM2INT(rb_Integer(ival));
2360 n = gBuiltinParameters->nvdwCutoffPars;
2361 else if (mol->par != NULL)
2362 n = mol->par->nvdwCutoffPars;
2364 if (idx < -n || idx >= n)
2365 rb_raise(rb_eMolbyError, "Dihedral parameter index (%d) out of range", idx);
2368 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwCutoffParType, idx);
2373 * element(idx) -> ParameterRef
2374 * element(t1) -> ParameterRef
2376 * In the first form, the index-th element parameter record is returned. In the second
2377 * form, the element parameter for t1 is looked up (the last index first). t1
2378 * is the element name string (up to 4 characters).
2379 * Unlike other Parameter methods, this is used only for the global parameter.
2382 s_Parameter_Element(VALUE self, VALUE ival)
2385 if (rb_obj_is_kind_of(ival, rb_cNumeric)) {
2386 int n = gCountElementParameters;
2387 idx1 = NUM2INT(rb_Integer(ival));
2388 if (idx1 < -n || idx1 >= n)
2389 rb_raise(rb_eMolbyError, "Element parameter index (%d) out of range", idx1);
2392 return ValueFromMoleculeWithParameterTypeAndIndex(NULL, kElementParType, idx1);
2397 strncpy(name, StringValuePtr(ival), 4);
2399 for (i = gCountElementParameters - 1, ep = gElementParameters + i; i >= 0; i--, ep--) {
2400 if (strncmp(ep->name, name, 4) == 0)
2401 return ValueFromMoleculeWithParameterTypeAndIndex(NULL, kElementParType, i);
2411 * Returns the number of bond parameters.
2414 s_Parameter_Nbonds(VALUE self)
2417 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2419 n = gBuiltinParameters->nbondPars;
2420 else if (mol->par != NULL)
2421 n = mol->par->nbondPars;
2428 * nangles -> Integer
2430 * Returns the number of angle parameters.
2433 s_Parameter_Nangles(VALUE self)
2436 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2438 n = gBuiltinParameters->nanglePars;
2439 else if (mol->par != NULL)
2440 n = mol->par->nanglePars;
2447 * ndihedrals -> Integer
2449 * Returns the number of dihedral parameters.
2452 s_Parameter_Ndihedrals(VALUE self)
2455 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2457 n = gBuiltinParameters->ndihedralPars;
2458 else if (mol->par != NULL)
2459 n = mol->par->ndihedralPars;
2466 * nimpropers -> Integer
2468 * Returns the number of improper parameters.
2471 s_Parameter_Nimpropers(VALUE self)
2474 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2476 n = gBuiltinParameters->nimproperPars;
2477 else if (mol->par != NULL)
2478 n = mol->par->nimproperPars;
2487 * Returns the number of vdw parameters.
2490 s_Parameter_Nvdws(VALUE self)
2493 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2495 n = gBuiltinParameters->nvdwPars;
2496 else if (mol->par != NULL)
2497 n = mol->par->nvdwPars;
2504 * nvdw_pairs -> Integer
2506 * Returns the number of vdw pair parameters.
2509 s_Parameter_NvdwPairs(VALUE self)
2512 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2514 n = gBuiltinParameters->nvdwpPars;
2515 else if (mol->par != NULL)
2516 n = mol->par->nvdwpPars;
2523 * nvdw_cutoffs -> Integer
2525 * Returns the number of vdw cutoff parameters.
2528 s_Parameter_NvdwCutoffs(VALUE self)
2531 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2533 n = gBuiltinParameters->nvdwCutoffPars;
2534 else if (mol->par != NULL)
2535 n = mol->par->nvdwCutoffPars;
2542 * nelements -> Integer
2544 * Returns the number of element parameters.
2547 s_Parameter_Nelements(VALUE self)
2549 return INT2NUM(gCountElementParameters);
2554 * bonds -> ParEnumerable
2556 * Returns a ParEnumerable value that (formally) points to the collection of bond parameters.
2557 * Parameter.bonds[x] is equivalent to Parameter.bond(x). ParEnumerable class is
2558 * useful when all accessible parameters should be examined by use of 'each' method.
2561 s_Parameter_Bonds(VALUE self)
2563 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2564 return s_NewParEnumerableValueFromMoleculeAndType(mol, kBondParType);
2569 * angles -> ParEnumerable
2571 * Returns a ParEnumerable value that (formally) points to the collection of angle parameters.
2572 * Parameter.angles[x] is equivalent to Parameter.angle(x). ParEnumerable class is
2573 * useful when all accessible parameters should be examined by use of 'each' method.
2576 s_Parameter_Angles(VALUE self)
2578 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2579 return s_NewParEnumerableValueFromMoleculeAndType(mol, kAngleParType);
2584 * dihedrals -> ParEnumerable
2586 * Returns a ParEnumerable value that (formally) points to the collection of dihedral parameters.
2587 * Parameter.dihedrals[x] is equivalent to Parameter.dihedral(x). ParEnumerable class is
2588 * useful when all accessible parameters should be examined by use of 'each' method.
2591 s_Parameter_Dihedrals(VALUE self)
2593 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2594 return s_NewParEnumerableValueFromMoleculeAndType(mol, kDihedralParType);
2599 * impropers -> ParEnumerable
2601 * Returns a ParEnumerable value that (formally) points to the collection of improper parameters.
2602 * Parameter.impropers[x] is equivalent to Parameter.improper(x). ParEnumerable class is
2603 * useful when all accessible parameters should be examined by use of 'each' method.
2606 s_Parameter_Impropers(VALUE self)
2608 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2609 return s_NewParEnumerableValueFromMoleculeAndType(mol, kImproperParType);
2614 * vdws -> ParEnumerable
2616 * Returns a ParEnumerable value that (formally) points to the collection of vdw parameters.
2617 * Parameter.vdws[x] is equivalent to Parameter.vdw(x). ParEnumerable class is
2618 * useful when all accessible parameters should be examined by use of 'each' method.
2621 s_Parameter_Vdws(VALUE self)
2623 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2624 return s_NewParEnumerableValueFromMoleculeAndType(mol, kVdwParType);
2629 * vdw_pairs -> ParEnumerable
2631 * Returns a ParEnumerable value that (formally) points to the collection of vdw pair parameters.
2632 * Parameter.vdw_pairs[x] is equivalent to Parameter.vdw_pair(x). ParEnumerable class is
2633 * useful when all accessible parameters should be examined by use of 'each' method.
2636 s_Parameter_VdwPairs(VALUE self)
2638 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2639 return s_NewParEnumerableValueFromMoleculeAndType(mol, kVdwPairParType);
2644 * vdw_cutoffs -> ParEnumerable
2646 * Returns a ParEnumerable value that (formally) points to the collection of vdw cutoff parameters.
2647 * Parameter.vdw_cutoffs[x] is equivalent to Parameter.vdw_cutoff(x). ParEnumerable class is
2648 * useful when all accessible parameters should be examined by use of 'each' method.
2651 s_Parameter_VdwCutoffs(VALUE self)
2653 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2654 return s_NewParEnumerableValueFromMoleculeAndType(mol, kVdwCutoffParType);
2659 * elements -> ParEnumerable
2661 * Returns a ParEnumerable value that (formally) points to the collection of element parameters.
2662 * Parameter.elements[x] is equivalent to Parameter.element(x). ParEnumerable class is
2663 * useful when all accessible parameters should be examined by use of 'each' method.
2666 s_Parameter_Elements(VALUE self)
2668 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2669 return s_NewParEnumerableValueFromMoleculeAndType(mol, kElementParType);
2673 s_Parameter_Lookup_sub(int argc, VALUE *argv, int parType, Molecule *mol)
2675 VALUE atval, optval;
2678 int i, n, idx, flags, is_global;
2680 rb_scan_args(argc, argv, "1*", &atval, &optval);
2682 /* Get the atom types */
2684 case kBondParType: n = 2; break;
2685 case kAngleParType: n = 3; break;
2686 case kDihedralParType: n = 4; break;
2687 case kImproperParType: n = 4; break;
2688 case kVdwParType: n = 1; break;
2689 case kVdwPairParType: n = 2; break;
2690 default: return Qnil;
2692 s_ScanAtomTypes(atval, n, t);
2693 for (i = 0; i < n; i++) {
2694 if (t[i] < kAtomTypeMinimum) {
2695 /* Explicit atom index */
2697 rb_raise(rb_eMolbyError, "Explicit atom index (%d) is invalid for global parameters", t[i]);
2698 if (t[i] >= mol->natoms)
2699 rb_raise(rb_eMolbyError, "Atom index (%d) out of range", t[i]);
2701 t[i] = ATOM_AT_INDEX(mol->atoms, t[i])->type;
2705 /* Analyze options */
2707 n = RARRAY_LEN(optval);
2708 for (i = 0; i < n; i++) {
2709 VALUE oval = RARRAY_PTR(optval)[i];
2710 if (oval == ID2SYM(rb_intern("global")))
2711 flags |= kParameterLookupGlobal;
2712 else if (oval == ID2SYM(rb_intern("local")))
2713 flags |= kParameterLookupLocal;
2714 else if (oval == ID2SYM(rb_intern("missing")))
2715 flags |= kParameterLookupMissing;
2716 else if (oval == ID2SYM(rb_intern("nowildcard")))
2717 flags |= kParameterLookupNoWildcard;
2718 else if (oval == ID2SYM(rb_intern("nobasetype")))
2719 flags |= kParameterLookupNoBaseAtomType;
2720 else if (oval == ID2SYM(rb_intern("create")))
2724 flags = kParameterLookupGlobal | kParameterLookupLocal;
2729 case kBondParType: {
2732 bp = ParameterLookupBondPar(mol->par, t[0], t[1], ii[0], ii[1], flags);
2734 idx = bp - mol->par->bondPars;
2738 bp = ParameterLookupBondPar(gBuiltinParameters, t[0], t[1], -1, -1, flags);
2740 idx = bp - gBuiltinParameters->bondPars;
2745 case kAngleParType: {
2748 ap = ParameterLookupAnglePar(mol->par, t[0], t[1], t[2], ii[0], ii[1], ii[2], flags);
2750 idx = ap - mol->par->anglePars;
2754 ap = ParameterLookupAnglePar(gBuiltinParameters, t[0], t[1], t[2], -1, -1, -1, flags);
2756 idx = ap - gBuiltinParameters->anglePars;
2761 case kDihedralParType: {
2764 tp = ParameterLookupDihedralPar(mol->par, t[0], t[1], t[2], t[3], ii[0], ii[1], ii[2], ii[3], flags);
2766 idx = tp - mol->par->dihedralPars;
2770 tp = ParameterLookupDihedralPar(gBuiltinParameters, t[0], t[1], t[2], t[3], -1, -1, -1, -1, flags);
2772 idx = tp - gBuiltinParameters->dihedralPars;
2777 case kImproperParType: {
2780 tp = ParameterLookupImproperPar(mol->par, t[0], t[1], t[2], t[3], ii[0], ii[1], ii[2], ii[3], flags);
2782 idx = tp - mol->par->improperPars;
2786 tp = ParameterLookupImproperPar(gBuiltinParameters, t[0], t[1], t[2], t[3], -1, -1, -1, -1, flags);
2788 idx = tp - gBuiltinParameters->improperPars;
2796 vp = ParameterLookupVdwPar(mol->par, t[0], flags);
2798 idx = vp - mol->par->vdwPars;
2802 vp = ParameterLookupVdwPar(gBuiltinParameters, t[0], flags);
2804 idx = vp - gBuiltinParameters->vdwPars;
2809 case kVdwPairParType: {
2812 vp = ParameterLookupVdwPairPar(mol->par, t[0], t[1], flags);
2814 idx = vp - mol->par->vdwpPars;
2818 vp = ParameterLookupVdwPairPar(gBuiltinParameters, t[0], t[1], flags);
2820 idx = vp - gBuiltinParameters->vdwpPars;
2829 if ((flags & 256) == 0 || mol == NULL || mol->par == NULL)
2832 /* Insert a new parameter record */
2834 Int count = ParameterGetCountForType(mol->par, parType);
2835 IntGroup *ig = IntGroupNewWithPoints(count, 1, -1);
2836 MolActionCreateAndPerform(mol, gMolActionAddParameters, parType, ig, 0, NULL);
2837 IntGroupRelease(ig);
2840 /* Set atom types */
2841 up = ParameterGetUnionParFromTypeAndIndex(mol->par, parType, idx);
2846 up->bond.type1 = t[0];
2847 up->bond.type2 = t[1];
2850 up->angle.type1 = t[0];
2851 up->angle.type2 = t[1];
2852 up->angle.type3 = t[2];
2854 case kDihedralParType:
2855 case kImproperParType:
2856 up->torsion.type1 = t[0];
2857 up->torsion.type2 = t[1];
2858 up->torsion.type3 = t[2];
2859 up->torsion.type4 = t[3];
2862 up->vdw.type1 = t[0];
2864 case kVdwPairParType:
2865 up->vdwp.type1 = t[0];
2866 up->vdwp.type2 = t[1];
2873 return ValueFromMoleculeWithParameterTypeAndIndex(mol, parType, idx);
2878 * lookup(par_type, atom_types, options, ...) -> ParameterRef
2879 * lookup(par_type, atom_type_string, options, ...) -> ParameterRef
2881 * Find the parameter record that matches the given atom types. The atom types are given
2882 * either as an array of string, or a single string delimited by whitespaces or hyphens.
2883 * Options are given as symbols. Valid values are :global (look for global parameters), :local
2884 * (look for local parameters), :missing (look for missing parameters), :nowildcard (do not
2885 * allow wildcard matching), :nobasetype (the base type does not match for the variant types)
2888 s_Parameter_LookUp(int argc, VALUE *argv, VALUE self)
2891 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2893 rb_raise(rb_eMolbyError, "parameter type and atom types must be specified");
2894 parType = s_ParTypeFromValue(argv[0]);
2895 return s_Parameter_Lookup_sub(argc - 1, argv + 1, parType, mol);
2900 * self == parameter -> boolean
2902 * True if the parameters point to the same parameter table.
2905 s_Parameter_Equal(VALUE self, VALUE val)
2907 if (rb_obj_is_kind_of(val, rb_cParameter)) {
2908 return (s_MoleculeFromParameterOrParEnumerableValue(self) == s_MoleculeFromParameterOrParEnumerableValue(val) ? Qtrue : Qfalse);
2909 } else return Qfalse;
2912 #pragma mark ====== ParEnumerable Class ======
2914 /* The ParEnumerable class encapsulates the Molecule (not Parameter) pointer
2915 and the parameter type. If the Molecule is NULL, then it refers to the
2916 global (built-in) parameters. Note that, even when the Molecule is not NULL,
2917 the global parameters are always accessible. */
2919 typedef struct ParEnumerable {
2921 Int parType; /* Same as parType in ParameterRef */
2924 static ParEnumerable *
2925 s_ParEnumerableNew(Molecule *mol, Int parType)
2927 ParEnumerable *pen = (ParEnumerable *)calloc(sizeof(ParEnumerable), 1);
2931 MoleculeRetain(mol);
2932 pen->parType = parType;
2938 s_ParEnumerableRelease(ParEnumerable *pen)
2941 if (pen->mol != NULL)
2942 MoleculeRelease(pen->mol);
2948 s_MoleculeFromParEnumerableValue(VALUE val)
2951 Data_Get_Struct(val, ParEnumerable, pen);
2956 s_NewParEnumerableValueFromMoleculeAndType(Molecule *mol, Int parType)
2958 ParEnumerable *pen = s_ParEnumerableNew(mol, parType);
2960 rb_raise(rb_eMolbyError, "cannot allocate ParEnumerable record");
2961 return Data_Wrap_Struct(rb_cParEnumerable, 0, (void (*)(void *))s_ParEnumerableRelease, pen);
2966 * par_type -> String
2968 * Get the parameter type, like "bond", "angle", etc.
2971 s_ParEnumerable_ParType(VALUE self) {
2974 Data_Get_Struct(self, ParEnumerable, pen);
2976 if (tp == kElementParType)
2977 return rb_str_new2("element");
2978 tp -= kFirstParType;
2979 if (tp >= 0 && tp < sizeof(s_ParameterTypeNames) / sizeof(s_ParameterTypeNames[0]))
2980 return rb_str_new2(s_ParameterTypeNames[tp]);
2981 else rb_raise(rb_eMolbyError, "Internal error: parameter type tag is out of range (%d)", tp);
2986 * self[idx] -> ParameterRef
2988 * Call the accessor of the Parameter object from which this ParEnumerable object is derived from.
2989 * Thus, if self is "bond" type, self[idx] is equivalent to p.bond(idx), where p is the
2990 * parent Parameter object of self.
2992 * <b>See Also</b>: Parameter#bond, Parameter#angle, Parameter#dihedral, Parameter#improper,
2993 * Parameter#vdw, Parameter#vdw_pair, Parameter#vdw_cutoff, Parameter#element.
2996 s_ParEnumerable_Aref(VALUE self, VALUE ival)
2999 Data_Get_Struct(self, ParEnumerable, pen);
3000 switch (pen->parType) {
3001 /* s_Parameter_XXXX() also accepts ParEnumerable argument */
3002 case kBondParType: return s_Parameter_Bond(self, ival);
3003 case kAngleParType: return s_Parameter_Angle(self, ival);
3004 case kDihedralParType: return s_Parameter_Dihedral(self, ival);
3005 case kImproperParType: return s_Parameter_Improper(self, ival);
3006 case kVdwParType: return s_Parameter_Vdw(self, ival);
3007 case kVdwPairParType: return s_Parameter_VdwPair(self, ival);
3008 case kVdwCutoffParType: return s_Parameter_VdwCutoff(self, ival);
3009 case kElementParType: return s_Parameter_Element(self, ival);
3011 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3013 return Qnil; /* Not reached */
3020 * Returns the number of parameters included in this enumerable.
3023 s_ParEnumerable_Length(VALUE self)
3026 Data_Get_Struct(self, ParEnumerable, pen);
3027 switch (pen->parType) {
3028 /* s_Parameter_XXXX() also accepts ParEnumerable argument */
3029 case kBondParType: return s_Parameter_Nbonds(self);
3030 case kAngleParType: return s_Parameter_Nangles(self);
3031 case kDihedralParType: return s_Parameter_Ndihedrals(self);
3032 case kImproperParType: return s_Parameter_Nimpropers(self);
3033 case kVdwParType: return s_Parameter_Nvdws(self);
3034 case kVdwPairParType: return s_Parameter_NvdwPairs(self);
3035 case kVdwCutoffParType: return s_Parameter_NvdwCutoffs(self);
3036 case kElementParType: return s_Parameter_Nelements(self);
3038 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3040 return Qnil; /* Not reached */
3047 * Call the block for each parameter, passing a ParameterRef object as a block argument.
3050 s_ParEnumerable_Each(VALUE self)
3056 Data_Get_Struct(self, ParEnumerable, pen);
3057 if (pen->parType == kElementParType)
3058 n = gCountElementParameters;
3060 switch (pen->parType) {
3061 case kBondParType: ofs = offsetof(Parameter, nbondPars); break;
3062 case kAngleParType: ofs = offsetof(Parameter, nanglePars); break;
3063 case kDihedralParType: ofs = offsetof(Parameter, ndihedralPars); break;
3064 case kImproperParType: ofs = offsetof(Parameter, nimproperPars); break;
3065 case kVdwParType: ofs = offsetof(Parameter, nvdwPars); break;
3066 case kVdwPairParType: ofs = offsetof(Parameter, nvdwpPars); break;
3067 case kVdwCutoffParType: ofs = offsetof(Parameter, nvdwCutoffPars); break;
3069 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3071 if (pen->mol == NULL)
3072 n = *((Int *)((char *)gBuiltinParameters + ofs));
3073 else if (pen->mol->par != NULL)
3074 n = *((Int *)((char *)(pen->mol->par) + ofs));
3077 aval = ValueFromMoleculeWithParameterTypeAndIndex(pen->mol, pen->parType, 0);
3078 Data_Get_Struct(aval, ParameterRef, pref);
3079 for (i = 0; i < n; i++) {
3088 * reverse_each {|pref| ...}
3090 * Call the block for each parameter in the reverse order, passing a ParameterRef object as a block argument.
3093 s_ParEnumerable_ReverseEach(VALUE self)
3099 Data_Get_Struct(self, ParEnumerable, pen);
3100 if (pen->parType == kElementParType)
3101 n = gCountElementParameters;
3103 switch (pen->parType) {
3104 case kBondParType: ofs = offsetof(Parameter, nbondPars); break;
3105 case kAngleParType: ofs = offsetof(Parameter, nanglePars); break;
3106 case kDihedralParType: ofs = offsetof(Parameter, ndihedralPars); break;
3107 case kImproperParType: ofs = offsetof(Parameter, nimproperPars); break;
3108 case kVdwParType: ofs = offsetof(Parameter, nvdwPars); break;
3109 case kVdwPairParType: ofs = offsetof(Parameter, nvdwpPars); break;
3110 case kVdwCutoffParType: ofs = offsetof(Parameter, nvdwCutoffPars); break;
3112 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3114 if (pen->mol == NULL)
3115 n = *((Int *)((char *)gBuiltinParameters + ofs));
3116 else if (pen->mol->par != NULL)
3117 n = *((Int *)((char *)(pen->mol->par) + ofs));
3120 aval = ValueFromMoleculeWithParameterTypeAndIndex(pen->mol, pen->parType, 0);
3121 Data_Get_Struct(aval, ParameterRef, pref);
3122 for (i = n - 1; i >= 0; i--) {
3131 * insert(idx = nil, pref = nil) -> ParameterRef
3133 * Insert a new parameter at the specified position (if idx is nil, then at the end).
3134 * If a ParameterRef is given, then the content of the parameter is copied to the new parameter,
3135 * and the parameter is set as molecule-local. Otherwise, the new parameter is blank, and the
3136 * parameter is left undefined.
3137 * Throws an exception if ParEnumerable points to the global parameter.
3140 s_ParEnumerable_Insert(int argc, VALUE *argv, VALUE self)
3148 Data_Get_Struct(self, ParEnumerable, pen);
3149 if (pen->mol == NULL)
3150 rb_raise(rb_eMolbyError, "the global parameters cannot be modified");
3151 n = ParameterGetCountForType(pen->mol->par, pen->parType);
3152 rb_scan_args(argc, argv, "02", &ival, &pval);
3154 i = NUM2INT(rb_Integer(ival));
3156 rb_raise(rb_eMolbyError, "the parameter index (%d) out of range (should be 0..%d)", i, n);
3161 UnionPar *up = s_UnionParFromValue(pval, &type, 0);
3162 if (up == NULL || type != pen->parType)
3163 rb_raise(rb_eMolbyError, "the parameter specification is not correct");
3164 ParameterCopyOneWithType(&u, up, pen->parType);
3167 memset(&u, 0, sizeof(u));
3170 ig = IntGroupNewWithPoints(n, 1, -1);
3171 ParameterInsert(pen->mol->par, pen->parType, &u, ig);
3173 act = MolActionNew(gMolActionDeleteParameters, pen->parType, ig);
3174 MolActionCallback_registerUndo(pen->mol, act);
3175 MolActionRelease(act);
3177 IntGroupRelease(ig);
3178 return ValueFromMoleculeWithParameterTypeAndIndex(pen->mol, pen->parType, n);
3186 * Delete the parameter(s) specified by the argument.
3189 s_ParEnumerable_Delete(VALUE self, VALUE ival)
3194 Data_Get_Struct(self, ParEnumerable, pen);
3195 if (pen->mol == NULL)
3196 rb_raise(rb_eMolbyError, "the global parameters cannot be modified");
3197 n = ParameterGetCountForType(pen->mol->par, pen->parType);
3198 if (rb_obj_is_kind_of(ival, rb_cInteger)) {
3199 ig = IntGroupNewWithPoints(NUM2INT(ival), 1, -1);
3202 ig = IntGroupFromValue(ival);
3203 if ((i = IntGroupGetCount(ig)) == 0) {
3204 IntGroupRelease(ig);
3208 if ((i = IntGroupGetNthPoint(ig, i - 1)) >= n)
3209 rb_raise(rb_eMolbyError, "the parameter index (%d) out of range (should be 0..%d)", i, n);
3212 MolActionCreateAndPerform(pen->mol, gMolActionDeleteParameters, pen->parType, ig);
3213 IntGroupRelease(ig);
3219 * lookup(atom_types, options, ...) -> ParameterRef
3220 * lookup(atom_type_string, options, ...) -> ParameterRef
3222 * Find the parameter record that matches the given atom types. The arguments are
3223 * the same as Parameter#lookup, except for the parameter type which is implicitly
3227 s_ParEnumerable_LookUp(int argc, VALUE *argv, VALUE self)
3230 Data_Get_Struct(self, ParEnumerable, pen);
3231 return s_Parameter_Lookup_sub(argc, argv, pen->parType, pen->mol);
3236 * self == parEnumerable -> boolean
3238 * True if the arguments point to the same parameter table and type.
3241 s_ParEnumerable_Equal(VALUE self, VALUE val)
3243 if (rb_obj_is_kind_of(val, rb_cParEnumerable)) {
3244 ParEnumerable *pen1, *pen2;
3245 Data_Get_Struct(self, ParEnumerable, pen1);
3246 Data_Get_Struct(val, ParEnumerable, pen2);
3247 return (pen1->mol == pen2->mol && pen1->parType == pen2->parType) ? Qtrue : Qfalse;
3248 } else return Qfalse;
3251 #pragma mark ====== AtomRef Class ======
3253 /* Forward declaration for register undo */
3254 static VALUE s_Molecule_RegisterUndo(int argc, VALUE *argv, VALUE self);
3256 /* Ruby string "set_atom_attr" */
3257 static VALUE s_SetAtomAttrString;
3260 s_AtomIndexFromValue(VALUE self, Atom **app, Molecule **mpp)
3264 Data_Get_Struct(self, AtomRef, aref);
3265 idx = (aref->idx >= 0 ? aref->idx : aref->mol->natoms + aref->idx);
3266 if (idx < 0 || idx >= aref->mol->natoms)
3267 rb_raise(rb_eMolbyError, "atom index out of range (%d; should be %d..%d)", aref->idx, -aref->mol->natoms, aref->mol->natoms - 1);
3269 *app = aref->mol->atoms + idx;
3276 s_AtomFromValue(VALUE self)
3279 s_AtomIndexFromValue(self, &ap, NULL);
3284 s_AtomAndMoleculeFromValue(VALUE self, Molecule **mpp)
3287 s_AtomIndexFromValue(self, &ap, mpp);
3292 s_NotifyModificationForAtomRef(VALUE self)
3295 Data_Get_Struct(self, AtomRef, aref);
3296 MoleculeIncrementModifyCount(aref->mol);
3300 s_RegisterUndoForAtomAttrChange(VALUE self, VALUE key, VALUE val, VALUE oldval)
3303 Data_Get_Struct(self, AtomRef, aref);
3304 if (MolActionCallback_isUndoRegistrationEnabled(aref->mol) && !RTEST(rb_funcall(val, s_ID_equal, 1, oldval))) {
3307 act = MolActionNew(SCRIPT_ACTION("rrr"), "set_atom_attr", INT2NUM(aref->idx), key, oldval);
3308 MolActionCallback_registerUndo(aref->mol, act);
3309 MoleculeCallback_notifyModification(aref->mol, 0);
3310 /* Request MD rebuilt if necessary */
3311 if (key == s_AtomTypeSym || key == s_ChargeSym || key == s_WeightSym || key == s_FixPosSym || key == s_FixForceSym)
3312 aref->mol->needsMDRebuild = 1;
3317 ValueFromMoleculeAndIndex(Molecule *mol, int idx)
3320 aref = AtomRefNew(mol, idx);
3321 return Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
3325 s_AtomRef_GetMolecule(VALUE self)
3328 s_AtomIndexFromValue(self, NULL, &mpp);
3329 return ValueFromMolecule(mpp);
3332 static VALUE s_AtomRef_GetIndex(VALUE self) {
3333 return INT2NUM(s_AtomIndexFromValue(self, NULL, NULL));
3336 static VALUE s_AtomRef_GetSegSeq(VALUE self) {
3337 return INT2NUM(s_AtomFromValue(self)->segSeq);
3340 static VALUE s_AtomRef_GetSegName(VALUE self) {
3341 char *p = s_AtomFromValue(self)->segName;
3342 return rb_str_new(p, strlen_limit(p, 4));
3345 static VALUE s_AtomRef_GetResSeq(VALUE self) {
3346 return INT2NUM(s_AtomFromValue(self)->resSeq);
3349 static VALUE s_AtomRef_GetResName(VALUE self) {
3350 char *p = s_AtomFromValue(self)->resName;
3351 return rb_str_new(p, strlen_limit(p, 4));
3354 static VALUE s_AtomRef_GetName(VALUE self) {
3355 char *p = s_AtomFromValue(self)->aname;
3356 return rb_str_new(p, strlen_limit(p, 4));
3359 static VALUE s_AtomRef_GetAtomType(VALUE self) {
3360 int type = s_AtomFromValue(self)->type;
3361 char *p = (type == 0 ? "" : AtomTypeDecodeToString(type, NULL));
3362 return rb_str_new(p, strlen_limit(p, 6));
3365 static VALUE s_AtomRef_GetCharge(VALUE self) {
3366 return rb_float_new(s_AtomFromValue(self)->charge);
3369 static VALUE s_AtomRef_GetWeight(VALUE self) {
3370 return rb_float_new(s_AtomFromValue(self)->weight);
3373 static VALUE s_AtomRef_GetElement(VALUE self) {
3374 char *p = s_AtomFromValue(self)->element;
3375 return rb_str_new(p, strlen_limit(p, 4));
3378 static VALUE s_AtomRef_GetAtomicNumber(VALUE self) {
3379 return INT2NUM(s_AtomFromValue(self)->atomicNumber);
3382 static VALUE s_AtomRef_GetConnects(VALUE self) {
3385 Atom *ap = s_AtomFromValue(self);
3386 retval = rb_ary_new();
3387 cp = AtomConnectData(&ap->connect);
3388 for (i = 0; i < ap->connect.count; i++)
3389 rb_ary_push(retval, INT2NUM(cp[i]));
3393 static VALUE s_AtomRef_GetR(VALUE self) {
3394 return ValueFromVector(&(s_AtomFromValue(self)->r));
3397 static VALUE s_AtomRef_GetX(VALUE self) {
3398 return rb_float_new(s_AtomFromValue(self)->r.x);
3401 static VALUE s_AtomRef_GetY(VALUE self) {
3402 return rb_float_new(s_AtomFromValue(self)->r.y);
3405 static VALUE s_AtomRef_GetZ(VALUE self) {
3406 return rb_float_new(s_AtomFromValue(self)->r.z);
3409 static Vector s_AtomRef_GetFractionalRAsVector(VALUE self) {
3413 s_AtomIndexFromValue(self, &ap, &mp);
3415 if (mp->cell != NULL)
3416 TransformVec(&r1, mp->cell->rtr, &r1);
3420 static VALUE s_AtomRef_GetFractionalR(VALUE self) {
3421 Vector r1 = s_AtomRef_GetFractionalRAsVector(self);
3422 return ValueFromVector(&r1);
3425 static VALUE s_AtomRef_GetFractionalX(VALUE self) {
3426 return rb_float_new(s_AtomRef_GetFractionalRAsVector(self).x);
3429 static VALUE s_AtomRef_GetFractionalY(VALUE self) {
3430 return rb_float_new(s_AtomRef_GetFractionalRAsVector(self).y);
3433 static VALUE s_AtomRef_GetFractionalZ(VALUE self) {
3434 return rb_float_new(s_AtomRef_GetFractionalRAsVector(self).z);
3437 static VALUE s_AtomRef_GetSigma(VALUE self) {
3438 return ValueFromVector(&(s_AtomFromValue(self)->sigma));
3441 static VALUE s_AtomRef_GetSigmaX(VALUE self) {
3442 return rb_float_new(s_AtomFromValue(self)->sigma.x);
3445 static VALUE s_AtomRef_GetSigmaY(VALUE self) {
3446 return rb_float_new(s_AtomFromValue(self)->sigma.y);
3449 static VALUE s_AtomRef_GetSigmaZ(VALUE self) {
3450 return rb_float_new(s_AtomFromValue(self)->sigma.z);
3453 static VALUE s_AtomRef_GetV(VALUE self) {
3454 return ValueFromVector(&(s_AtomFromValue(self)->v));
3457 static VALUE s_AtomRef_GetF(VALUE self) {
3458 return ValueFromVector(&(s_AtomFromValue(self)->f));
3461 static VALUE s_AtomRef_GetOccupancy(VALUE self) {
3462 return rb_float_new(s_AtomFromValue(self)->occupancy);
3465 static VALUE s_AtomRef_GetTempFactor(VALUE self) {
3466 return rb_float_new(s_AtomFromValue(self)->tempFactor);
3469 static VALUE s_AtomRef_GetAniso(VALUE self) {
3472 Atom *ap = s_AtomFromValue(self);
3473 if (ap->aniso == NULL)
3475 retval = rb_ary_new();
3476 for (i = 0; i < 6; i++)
3477 rb_ary_push(retval, rb_float_new(ap->aniso->bij[i]));
3478 if (ap->aniso->has_bsig) {
3479 rb_ary_push(retval, INT2NUM(0));
3480 for (i = 0; i < 6; i++)
3481 rb_ary_push(retval, rb_float_new(ap->aniso->bsig[i]));
3486 static VALUE s_AtomRef_GetSymop(VALUE self) {
3488 Atom *ap = s_AtomFromValue(self);
3489 if (!ap->symop.alive)
3491 retval = rb_ary_new();
3492 rb_ary_push(retval, INT2NUM(ap->symop.sym));
3493 rb_ary_push(retval, INT2NUM(ap->symop.dx));
3494 rb_ary_push(retval, INT2NUM(ap->symop.dy));
3495 rb_ary_push(retval, INT2NUM(ap->symop.dz));
3496 rb_ary_push(retval, INT2NUM(ap->symbase));
3500 static VALUE s_AtomRef_GetIntCharge(VALUE self) {
3501 return INT2NUM(s_AtomFromValue(self)->intCharge);
3504 static VALUE s_AtomRef_GetFixForce(VALUE self) {
3505 return rb_float_new(s_AtomFromValue(self)->fix_force * INTERNAL2KCAL);
3508 static VALUE s_AtomRef_GetFixPos(VALUE self) {
3509 return ValueFromVector(&(s_AtomFromValue(self)->fix_pos));
3512 static VALUE s_AtomRef_GetExclusion(VALUE self) {
3516 MDExclusion *exinfo;
3519 idx = s_AtomIndexFromValue(self, &ap, &mol);
3520 if (mol->par == NULL || mol->arena == NULL || mol->arena->is_initialized == 0 || mol->needsMDRebuild) {
3521 VALUE mval = ValueFromMolecule(mol);
3522 s_RebuildMDParameterIfNecessary(mval, Qnil);
3524 if (mol->arena->exinfo == NULL)
3526 exinfo = mol->arena->exinfo + idx;
3527 exlist = mol->arena->exlist;
3528 retval = rb_ary_new();
3529 aval = rb_ary_new();
3530 for (i = exinfo->index1; i < exinfo->index2; i++) /* 1-2 exclusion */
3531 rb_ary_push(aval, INT2NUM(exlist[i]));
3532 rb_ary_push(retval, aval);
3533 aval = rb_ary_new();
3534 for (i = exinfo->index2; i < exinfo->index3; i++) /* 1-3 exclusion */
3535 rb_ary_push(aval, INT2NUM(exlist[i]));
3536 rb_ary_push(retval, aval);
3537 aval = rb_ary_new();
3538 for (i = exinfo->index3; i < (exinfo + 1)->index0; i++) /* 1-4 exclusion */
3539 rb_ary_push(aval, INT2NUM(exlist[i]));
3540 rb_ary_push(retval, aval);
3544 static VALUE s_AtomRef_GetMMExclude(VALUE self) {
3545 return INT2NUM(s_AtomFromValue(self)->mm_exclude);
3548 static VALUE s_AtomRef_GetPeriodicExclude(VALUE self) {
3549 return INT2NUM(s_AtomFromValue(self)->periodic_exclude);
3552 static VALUE s_AtomRef_GetHidden(VALUE self) {
3553 return ((s_AtomFromValue(self)->exflags & kAtomHiddenFlag) != 0 ? Qtrue : Qfalse);
3556 static VALUE s_AtomRef_GetAnchorList(VALUE self) {
3559 Atom *ap = s_AtomFromValue(self);
3560 if (ap->anchor == NULL)
3562 count = ap->anchor->connect.count;
3563 retval = rb_ary_new2(count * 2);
3564 cp = AtomConnectData(&ap->anchor->connect);
3565 for (i = 0; i < count; i++) {
3566 rb_ary_store(retval, i, INT2NUM(cp[i]));
3567 rb_ary_store(retval, i + count, rb_float_new(ap->anchor->coeffs[i]));
3572 static VALUE s_AtomRef_SetIndex(VALUE self, VALUE val) {
3573 rb_raise(rb_eMolbyError, "index cannot be directly set");
3577 static VALUE s_AtomRef_SetSegSeq(VALUE self, VALUE val) {
3578 VALUE oval = s_AtomRef_GetSegSeq(self);
3579 val = rb_Integer(val);
3580 s_AtomFromValue(self)->segSeq = NUM2INT(val);
3581 s_RegisterUndoForAtomAttrChange(self, s_SegSeqSym, val, oval);
3585 static VALUE s_AtomRef_SetSegName(VALUE self, VALUE val) {
3586 char *p = StringValuePtr(val);
3587 VALUE oval = s_AtomRef_GetSegName(self);
3588 strncpy(s_AtomFromValue(self)->segName, p, 4);
3589 s_RegisterUndoForAtomAttrChange(self, s_SegNameSym, val, oval);
3593 static VALUE s_AtomRef_SetResSeqOrResName(VALUE self, VALUE val) {
3594 rb_raise(rb_eMolbyError, "residue number/names cannot be directly set. Use Molecule#assign_residue instead.");
3595 return val; /* Not reached */
3598 static VALUE s_AtomRef_SetName(VALUE self, VALUE val) {
3599 Atom *ap = s_AtomFromValue(self);
3600 char *p = StringValuePtr(val);
3601 VALUE oval = s_AtomRef_GetName(self);
3602 if (ap->anchor != NULL && p[0] == '_')
3603 rb_raise(rb_eMolbyError, "please avoid a name beginning with '_' for a pi anchor, because it causes some internal confusion.");
3604 strncpy(ap->aname, p, 4);
3605 s_RegisterUndoForAtomAttrChange(self, s_NameSym, val, oval);
3609 static VALUE s_AtomRef_SetAtomType(VALUE self, VALUE val) {
3611 char *p = StringValuePtr(val);
3612 VALUE oval = s_AtomRef_GetAtomType(self);
3613 int type = (p[0] == 0 ? 0 : AtomTypeEncodeToUInt(p));
3614 if (type != 0 && type < kAtomTypeMinimum)
3615 rb_raise(rb_eMolbyError, "Invalid atom type '%s'", p);
3616 s_AtomAndMoleculeFromValue(self, &mp)->type = type;
3617 mp->needsMDRebuild = 1;
3618 s_RegisterUndoForAtomAttrChange(self, s_AtomTypeSym, val, oval);
3622 static VALUE s_AtomRef_SetCharge(VALUE self, VALUE val) {
3624 VALUE oval = s_AtomRef_GetCharge(self);
3625 val = rb_Float(val);
3626 s_AtomAndMoleculeFromValue(self, &mp)->charge = NUM2DBL(val);
3627 mp->needsMDRebuild = 1;
3628 s_RegisterUndoForAtomAttrChange(self, s_ChargeSym, val, oval);
3632 static VALUE s_AtomRef_SetWeight(VALUE self, VALUE val) {
3634 VALUE oval = s_AtomRef_GetWeight(self);
3635 val = rb_Float(val);
3636 s_AtomAndMoleculeFromValue(self, &mp)->weight = NUM2DBL(val);
3637 mp->needsMDRebuild = 1;
3638 s_RegisterUndoForAtomAttrChange(self, s_WeightSym, val, oval);
3642 static VALUE s_AtomRef_SetElement(VALUE self, VALUE val) {
3645 Atom *ap = s_AtomAndMoleculeFromValue(self, &mp);
3646 char *p = StringValuePtr(val);
3647 VALUE oval = s_AtomRef_GetElement(self);
3648 ap->atomicNumber = ElementToInt(p);
3649 ElementToString(ap->atomicNumber, ap->element);
3650 if ((w = WeightForAtomicNumber(ap->atomicNumber)) > 0.0)
3652 s_RegisterUndoForAtomAttrChange(self, s_ElementSym, val, oval);
3653 mp->needsMDRebuild = 1;
3657 static VALUE s_AtomRef_SetAtomicNumber(VALUE self, VALUE val) {
3660 Atom *ap = s_AtomAndMoleculeFromValue(self, &mp);
3661 VALUE oval = s_AtomRef_GetAtomicNumber(self);
3662 val = rb_Integer(val);
3663 ap->atomicNumber = NUM2INT(val);
3664 ElementToString(ap->atomicNumber, ap->element);
3665 if ((w = WeightForAtomicNumber(ap->atomicNumber)) > 0.0)
3667 s_RegisterUndoForAtomAttrChange(self, s_AtomicNumberSym, val, oval);
3668 mp->needsMDRebuild = 1;
3672 static VALUE s_AtomRef_SetConnects(VALUE self, VALUE val) {
3673 rb_raise(rb_eMolbyError, "connection table cannot be directly set. Use Molecule#create_bond instead.");
3674 return val; /* Not reached */
3677 static VALUE s_AtomRef_SetR(VALUE self, VALUE val) {
3680 VALUE oval = s_AtomRef_GetR(self);
3681 VectorFromValue(val, &v);
3682 s_AtomAndMoleculeFromValue(self, &mp)->r = v;
3683 s_RegisterUndoForAtomAttrChange(self, s_RSym, val, oval);
3684 mp->needsMDCopyCoordinates = 1;
3688 static VALUE s_AtomRef_SetX(VALUE self, VALUE val) {
3691 VALUE oval = s_AtomRef_GetX(self);
3692 val = rb_Float(val);
3694 s_AtomAndMoleculeFromValue(self, &mp)->r.x = f;
3695 s_RegisterUndoForAtomAttrChange(self, s_XSym, val, oval);
3696 mp->needsMDCopyCoordinates = 1;
3700 static VALUE s_AtomRef_SetY(VALUE self, VALUE val) {
3703 VALUE oval = s_AtomRef_GetY(self);
3704 val = rb_Float(val);
3706 s_AtomAndMoleculeFromValue(self, &mp)->r.y = f;
3707 s_RegisterUndoForAtomAttrChange(self, s_YSym, val, oval);
3708 mp->needsMDCopyCoordinates = 1;
3712 static VALUE s_AtomRef_SetZ(VALUE self, VALUE val) {
3715 VALUE oval = s_AtomRef_GetZ(self);
3716 val = rb_Float(val);
3718 s_AtomAndMoleculeFromValue(self, &mp)->r.z = f;
3719 s_RegisterUndoForAtomAttrChange(self, s_ZSym, val, oval);
3720 mp->needsMDCopyCoordinates = 1;
3724 static VALUE s_AtomRef_SetFractionalR(VALUE self, VALUE val) {
3728 s_AtomIndexFromValue(self, &ap, &mp);
3730 VectorFromValue(val, &v);
3731 if (mp->cell != NULL)
3732 TransformVec(&v, mp->cell->tr, &v);
3734 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3735 mp->needsMDCopyCoordinates = 1;
3739 static VALUE s_AtomRef_SetFractionalX(VALUE self, VALUE val) {
3744 s_AtomIndexFromValue(self, &ap, &mp);
3746 val = rb_Float(val);
3748 if (mp->cell != NULL) {
3749 TransformVec(&v, mp->cell->rtr, &v);
3751 TransformVec(&v, mp->cell->tr, &v);
3754 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3755 mp->needsMDCopyCoordinates = 1;
3759 static VALUE s_AtomRef_SetFractionalY(VALUE self, VALUE val) {
3764 s_AtomIndexFromValue(self, &ap, &mp);
3766 val = rb_Float(val);
3768 if (mp->cell != NULL) {
3769 TransformVec(&v, mp->cell->rtr, &v);
3771 TransformVec(&v, mp->cell->tr, &v);
3774 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3775 mp->needsMDCopyCoordinates = 1;
3779 static VALUE s_AtomRef_SetFractionalZ(VALUE self, VALUE val) {
3784 s_AtomIndexFromValue(self, &ap, &mp);
3786 val = rb_Float(val);
3788 if (mp->cell != NULL) {
3789 TransformVec(&v, mp->cell->rtr, &v);
3791 TransformVec(&v, mp->cell->tr, &v);
3794 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3795 mp->needsMDCopyCoordinates = 1;
3799 static VALUE s_AtomRef_SetSigma(VALUE self, VALUE val) {
3802 VALUE oval = s_AtomRef_GetSigma(self);
3803 VectorFromValue(val, &v);
3804 s_AtomAndMoleculeFromValue(self, &mp)->sigma = v;
3805 s_RegisterUndoForAtomAttrChange(self, s_SigmaSym, val, oval);
3806 mp->needsMDCopyCoordinates = 1;
3810 static VALUE s_AtomRef_SetSigmaX(VALUE self, VALUE val) {
3813 VALUE oval = s_AtomRef_GetSigmaX(self);
3814 val = rb_Float(val);
3816 s_AtomAndMoleculeFromValue(self, &mp)->sigma.x = f;
3817 s_RegisterUndoForAtomAttrChange(self, s_SigmaXSym, val, oval);
3818 mp->needsMDCopyCoordinates = 1;
3822 static VALUE s_AtomRef_SetSigmaY(VALUE self, VALUE val) {
3825 VALUE oval = s_AtomRef_GetSigmaY(self);
3826 val = rb_Float(val);
3828 s_AtomAndMoleculeFromValue(self, &mp)->sigma.y = f;
3829 s_RegisterUndoForAtomAttrChange(self, s_SigmaYSym, val, oval);
3830 mp->needsMDCopyCoordinates = 1;
3834 static VALUE s_AtomRef_SetSigmaZ(VALUE self, VALUE val) {
3837 VALUE oval = s_AtomRef_GetSigmaZ(self);
3838 val = rb_Float(val);
3840 s_AtomAndMoleculeFromValue(self, &mp)->sigma.z = f;
3841 s_RegisterUndoForAtomAttrChange(self, s_SigmaZSym, val, oval);
3842 mp->needsMDCopyCoordinates = 1;
3846 static VALUE s_AtomRef_SetV(VALUE self, VALUE val) {
3850 VALUE oval = s_AtomRef_GetV(self);
3851 VectorFromValue(val, &v);
3852 s_AtomIndexFromValue(self, &ap, &mp);
3854 s_RegisterUndoForAtomAttrChange(self, s_VSym, val, oval);
3855 mp->needsMDCopyCoordinates = 1;
3859 static VALUE s_AtomRef_SetF(VALUE self, VALUE val) {
3862 VALUE oval = s_AtomRef_GetF(self);
3863 VectorFromValue(val, &v);
3864 s_AtomAndMoleculeFromValue(self, &mp)->f = v;
3865 s_RegisterUndoForAtomAttrChange(self, s_FSym, val, oval);
3866 mp->needsMDCopyCoordinates = 1;
3870 static VALUE s_AtomRef_SetOccupancy(VALUE self, VALUE val) {
3871 VALUE oval = s_AtomRef_GetOccupancy(self);
3873 val = rb_Float(val);
3874 s_AtomAndMoleculeFromValue(self, &mp)->occupancy = NUM2DBL(val);
3875 s_RegisterUndoForAtomAttrChange(self, s_OccupancySym, val, oval);
3876 mp->needsMDCopyCoordinates = 1; /* Occupancy can be used to exclude particular atoms from MM/MD */
3880 static VALUE s_AtomRef_SetTempFactor(VALUE self, VALUE val) {
3881 VALUE oval = s_AtomRef_GetTempFactor(self);
3882 val = rb_Float(val);
3883 s_AtomFromValue(self)->tempFactor = NUM2DBL(val);
3884 s_RegisterUndoForAtomAttrChange(self, s_TempFactorSym, val, oval);
3888 static VALUE s_AtomRef_SetAniso(VALUE self, VALUE val) {
3893 VALUE oval = s_AtomRef_GetAniso(self);
3894 Data_Get_Struct(self, AtomRef, aref);
3895 val = rb_funcall(val, rb_intern("to_a"), 0);
3896 n = RARRAY_LEN(val);
3897 valp = RARRAY_PTR(val);
3898 for (i = 0; i < 6; i++) {
3900 f[i] = NUM2DBL(rb_Float(valp[i]));
3904 type = NUM2INT(rb_Integer(valp[6]));
3907 for (i = 0; i < 6; i++)
3908 f[i + 6] = NUM2DBL(rb_Float(valp[i + 7]));
3910 for (i = 0; i < 6; i++)
3913 i = s_AtomIndexFromValue(self, NULL, NULL);
3914 MoleculeSetAniso(aref->mol, i, type, f[0], f[1], f[2], f[3], f[4], f[5], (n >= 13 ? f + 6 : NULL));
3915 s_RegisterUndoForAtomAttrChange(self, s_AnisoSym, val, oval);
3919 static VALUE s_AtomRef_SetSymop(VALUE self, VALUE val) {
3925 VALUE oval = s_AtomRef_GetSymop(self);
3926 i = s_AtomIndexFromValue(self, &ap, &mol);
3928 ival[0] = ival[1] = ival[2] = ival[3] = ival[4] = 0;
3930 val = rb_funcall(val, rb_intern("to_a"), 0);
3931 n = RARRAY_LEN(val);
3932 valp = RARRAY_PTR(val);
3933 for (i = 0; i < 5; i++) {
3935 if (valp[i] == Qnil)
3938 ival[i] = NUM2INT(rb_Integer(valp[i]));
3939 } else ival[i] = -100000;
3942 if (ival[0] != -100000 && (ival[0] < 0 || ival[0] >= mol->nsyms))
3943 rb_raise(rb_eMolbyError, "index of symmetry (%d) is out of range (should be 0..%d)", ival[0], mol->nsyms - 1);
3944 if (ival[4] != -100000 && (ival[4] < 0 || ival[4] >= mol->natoms))
3945 rb_raise(rb_eMolbyError, "atom index number (%d) is out of range (should be 0..%d)", ival[4], mol->natoms - 1);
3946 if (ap->symop.sym == ival[0] && ap->symop.dx == ival[1] && ap->symop.dy == ival[2] && ap->symop.dz == ival[3])
3947 return val; /* No need to change */
3948 if (ival[0] != -100000)
3949 ap->symop.sym = ival[0];
3950 if (ival[1] != -100000)
3951 ap->symop.dx = ival[1];
3952 if (ival[2] != -100000)
3953 ap->symop.dy = ival[2];
3954 if (ival[3] != -100000)
3955 ap->symop.dz = ival[3];
3956 ap->symop.alive = (SYMOP_ALIVE(ap->symop) != 0);
3957 if (ival[4] != -100000)
3958 ap->symbase = ival[4];
3959 if (ap->symop.alive && (ap->aniso != NULL || (ATOM_AT_INDEX(mol->atoms, ap->symbase))->aniso != NULL)) {
3960 /* The anisotropic parameters should be recalculated */
3961 VALUE oaval = s_AtomRef_GetAniso(self);
3962 MoleculeSetAnisoBySymop(mol, i);
3963 s_RegisterUndoForAtomAttrChange(self, s_AnisoSym, val, oaval);
3965 s_RegisterUndoForAtomAttrChange(self, s_SymopSym, val, oval);
3969 static VALUE s_AtomRef_SetIntCharge(VALUE self, VALUE val) {
3970 VALUE oval = s_AtomRef_GetIntCharge(self);
3971 val = rb_Integer(val);
3972 s_AtomFromValue(self)->intCharge = NUM2INT(val);
3973 s_RegisterUndoForAtomAttrChange(self, s_IntChargeSym, val, oval);
3977 static VALUE s_AtomRef_SetFixForce(VALUE self, VALUE val) {
3979 VALUE oval = s_AtomRef_GetFixForce(self);
3980 val = rb_Float(val);
3981 s_AtomAndMoleculeFromValue(self, &mp)->fix_force = NUM2DBL(val) * KCAL2INTERNAL;
3982 s_RegisterUndoForAtomAttrChange(self, s_FixForceSym, val, oval);
3983 mp->needsMDRebuild = 1;
3987 static VALUE s_AtomRef_SetFixPos(VALUE self, VALUE val) {
3990 VALUE oval = s_AtomRef_GetFixPos(self);
3991 VectorFromValue(val, &v);
3992 s_AtomAndMoleculeFromValue(self, &mp)->fix_pos = v;
3993 s_RegisterUndoForAtomAttrChange(self, s_FixPosSym, val, oval);
3994 mp->needsMDRebuild = 1;
3998 static VALUE s_AtomRef_SetExclusion(VALUE self, VALUE val) {
3999 rb_raise(rb_eMolbyError, "exclusion table is read-only.");
4000 return val; /* Not reached */
4003 static VALUE s_AtomRef_SetMMExclude(VALUE self, VALUE val) {
4004 VALUE oval = s_AtomRef_GetIntCharge(self);
4005 val = rb_Integer(val);
4006 s_AtomFromValue(self)->mm_exclude = NUM2INT(val);
4007 s_RegisterUndoForAtomAttrChange(self, s_MMExcludeSym, val, oval);
4011 static VALUE s_AtomRef_SetPeriodicExclude(VALUE self, VALUE val) {
4012 VALUE oval = s_AtomRef_GetIntCharge(self);
4013 val = rb_Integer(val);
4014 s_AtomFromValue(self)->periodic_exclude = NUM2INT(val);
4015 s_RegisterUndoForAtomAttrChange(self, s_PeriodicExcludeSym, val, oval);
4019 static VALUE s_AtomRef_SetHidden(VALUE self, VALUE val) {
4020 Atom *ap = s_AtomFromValue(self);
4021 VALUE oval = ((ap->exflags & kAtomHiddenFlag) != 0 ? Qtrue : Qfalse);
4023 ap->exflags |= kAtomHiddenFlag;
4025 ap->exflags &= ~kAtomHiddenFlag;
4027 s_RegisterUndoForAtomAttrChange(self, s_HiddenSym, val, oval);
4031 static VALUE s_AtomRef_SetAnchorList(VALUE self, VALUE val) {
4032 Int idx, i, j, k, n, *ip;
4039 MolAction **undoActions;
4040 memset(&ac, 0, sizeof(ac));
4041 idx = s_AtomIndexFromValue(self, &ap, &mol);
4042 oval = s_AtomRef_GetAnchorList(self);
4044 val = rb_ary_to_ary(val);
4045 n = RARRAY_LEN(val);
4048 if (ap->anchor != NULL) {
4049 AtomConnectResize(&ap->anchor->connect, 0);
4050 free(ap->anchor->coeffs);
4053 s_RegisterUndoForAtomAttrChange(self, s_AnchorListSym, val, oval);
4058 rb_raise(rb_eMolbyError, "set_anchor_list: the argument should have at least two atom indices");
4059 if (ap->aname[0] == '_')
4060 rb_raise(rb_eMolbyError, "please avoid a name beginning with '_' for a pi anchor, because it causes some internal confusion.");
4061 ip = (Int *)malloc(sizeof(Int) * n);
4063 for (i = 0; i < n; i++) {
4064 v = RARRAY_PTR(val)[i];
4065 if (rb_obj_is_kind_of(v, rb_cFloat))
4067 j = NUM2INT(rb_Integer(v));
4068 if (j < 0 || j >= mol->natoms)
4069 rb_raise(rb_eMolbyError, "set_anchor_list: atom index (%d) out of range", j);
4070 for (k = 0; k < i; k++) {
4072 rb_raise(rb_eMolbyError, "set_anchor_list: duplicate atom index (%d)", j);
4078 rb_raise(rb_eMolbyError, "set_anchor_list: the argument should have at least two atom indices");
4079 else if (i * 2 != n)
4080 rb_raise(rb_eMolbyError, "set_anchor_list: the weights should be given in the same number as the atom indices");
4081 dp = (Double *)malloc(sizeof(Double) * n / 2);
4082 for (i = 0; i < n / 2; i++) {
4083 dp[i] = NUM2DBL(rb_Float(RARRAY_PTR(val)[i + n / 2]));
4085 rb_raise(rb_eMolbyError, "set_anchor_list: the weights should be positive Floats");
4091 i = MoleculeSetPiAnchorList(mol, idx, n, ip, dp, &nUndoActions, &undoActions);
4095 rb_raise(rb_eMolbyError, "invalid argument");
4096 if (nUndoActions > 0) {
4097 for (i = 0; i < nUndoActions; i++) {
4098 MolActionCallback_registerUndo(mol, undoActions[i]);
4099 MolActionRelease(undoActions[i]);
4103 s_RegisterUndoForAtomAttrChange(self, s_AnchorListSym, val, oval);
4107 static struct s_AtomAttrDef {
4109 VALUE *symref; /* Address of s_IndexSymbol etc. */
4110 ID id; /* Will be set within InitMolby() */
4111 VALUE (*getter)(VALUE);
4112 VALUE (*setter)(VALUE, VALUE);
4113 } s_AtomAttrDefTable[] = {
4114 {"index", &s_IndexSym, 0, s_AtomRef_GetIndex, s_AtomRef_SetIndex},
4115 {"seg_seq", &s_SegSeqSym, 0, s_AtomRef_GetSegSeq, s_AtomRef_SetSegSeq},
4116 {"seg_name", &s_SegNameSym, 0, s_AtomRef_GetSegName, s_AtomRef_SetSegName},
4117 {"res_seq", &s_ResSeqSym, 0, s_AtomRef_GetResSeq, s_AtomRef_SetResSeqOrResName},
4118 {"res_name", &s_ResNameSym, 0, s_AtomRef_GetResName, s_AtomRef_SetResSeqOrResName},
4119 {"name", &s_NameSym, 0, s_AtomRef_GetName, s_AtomRef_SetName},
4120 {"atom_type", &s_AtomTypeSym, 0, s_AtomRef_GetAtomType, s_AtomRef_SetAtomType},
4121 {"charge", &s_ChargeSym, 0, s_AtomRef_GetCharge, s_AtomRef_SetCharge},
4122 {"weight", &s_WeightSym, 0, s_AtomRef_GetWeight, s_AtomRef_SetWeight},
4123 {"element", &s_ElementSym, 0, s_AtomRef_GetElement, s_AtomRef_SetElement},
4124 {"atomic_number", &s_AtomicNumberSym,0, s_AtomRef_GetAtomicNumber, s_AtomRef_SetAtomicNumber},
4125 {"connects", &s_ConnectsSym, 0, s_AtomRef_GetConnects, s_AtomRef_SetConnects},
4126 {"r", &s_RSym, 0, s_AtomRef_GetR, s_AtomRef_SetR},
4127 {"x", &s_XSym, 0, s_AtomRef_GetX, s_AtomRef_SetX},
4128 {"y", &s_YSym, 0, s_AtomRef_GetY, s_AtomRef_SetY},
4129 {"z", &s_ZSym, 0, s_AtomRef_GetZ, s_AtomRef_SetZ},
4130 {"fract_r", &s_FractRSym, 0, s_AtomRef_GetFractionalR, s_AtomRef_SetFractionalR},
4131 {"fract_x", &s_FractXSym, 0, s_AtomRef_GetFractionalX, s_AtomRef_SetFractionalX},
4132 {"fract_y", &s_FractYSym, 0, s_AtomRef_GetFractionalY, s_AtomRef_SetFractionalY},
4133 {"fract_z", &s_FractZSym, 0, s_AtomRef_GetFractionalZ, s_AtomRef_SetFractionalZ},
4134 {"sigma", &s_SigmaSym, 0, s_AtomRef_GetSigma, s_AtomRef_SetSigma},
4135 {"sigma_x", &s_SigmaXSym, 0, s_AtomRef_GetSigmaX, s_AtomRef_SetSigmaX},
4136 {"sigma_y", &s_SigmaYSym, 0, s_AtomRef_GetSigmaY, s_AtomRef_SetSigmaY},
4137 {"sigma_z", &s_SigmaZSym, 0, s_AtomRef_GetSigmaZ, s_AtomRef_SetSigmaZ},
4138 {"v", &s_VSym, 0, s_AtomRef_GetV, s_AtomRef_SetV},
4139 {"f", &s_FSym, 0, s_AtomRef_GetF, s_AtomRef_SetF},
4140 {"occupancy", &s_OccupancySym, 0, s_AtomRef_GetOccupancy, s_AtomRef_SetOccupancy},
4141 {"temp_factor", &s_TempFactorSym, 0, s_AtomRef_GetTempFactor, s_AtomRef_SetTempFactor},
4142 {"aniso", &s_AnisoSym, 0, s_AtomRef_GetAniso, s_AtomRef_SetAniso},
4143 {"symop", &s_SymopSym, 0, s_AtomRef_GetSymop, s_AtomRef_SetSymop},
4144 {"int_charge", &s_IntChargeSym, 0, s_AtomRef_GetIntCharge, s_AtomRef_SetIntCharge},
4145 {"fix_force", &s_FixForceSym, 0, s_AtomRef_GetFixForce, s_AtomRef_SetFixForce},
4146 {"fix_pos", &s_FixPosSym, 0, s_AtomRef_GetFixPos, s_AtomRef_SetFixPos},
4147 {"exclusion", &s_ExclusionSym, 0, s_AtomRef_GetExclusion, s_AtomRef_SetExclusion},
4148 {"mm_exclude", &s_MMExcludeSym, 0, s_AtomRef_GetMMExclude, s_AtomRef_SetMMExclude},
4149 {"periodic_exclude", &s_PeriodicExcludeSym, 0, s_AtomRef_GetPeriodicExclude, s_AtomRef_SetPeriodicExclude},
4150 {"hidden", &s_HiddenSym, 0, s_AtomRef_GetHidden, s_AtomRef_SetHidden},
4151 {"anchor_list", &s_AnchorListSym, 0, s_AtomRef_GetAnchorList, s_AtomRef_SetAnchorList},
4152 {NULL} /* Sentinel */
4156 s_AtomRef_SetAttr(VALUE self, VALUE key, VALUE value)
4160 if (TYPE(key) != T_SYMBOL) {
4161 kid = rb_intern(StringValuePtr(key));
4163 } else kid = SYM2ID(key);
4164 for (i = 0; s_AtomAttrDefTable[i].name != NULL; i++) {
4165 if (s_AtomAttrDefTable[i].id == kid) {
4166 if (value == Qundef)
4167 return (*(s_AtomAttrDefTable[i].getter))(self);
4169 return (*(s_AtomAttrDefTable[i].setter))(self, value);
4172 rb_raise(rb_eMolbyError, "unknown atom attribute \"%s\"", rb_id2name(kid));
4173 return Qnil; /* not reached */
4177 s_AtomRef_GetAttr(VALUE self, VALUE key)
4179 return s_AtomRef_SetAttr(self, key, Qundef);
4184 * self == atomRef -> boolean
4186 * True if the two references point to the same atom.
4189 s_AtomRef_Equal(VALUE self, VALUE val)
4191 if (rb_obj_is_kind_of(val, rb_cAtomRef)) {
4192 return (s_AtomFromValue(self) == s_AtomFromValue(val) ? Qtrue : Qfalse);
4193 } else return Qfalse;
4196 #pragma mark ====== MolEnumerable Class ======
4198 static int s_Molecule_AtomIndexFromValue(Molecule *, VALUE);
4202 * self[idx] -> AtomRef or Array of Integers
4204 * Get the idx-th atom, bond, etc. for the Molecule from which this MolEnuerable object is
4205 * derived from. For the atom, the return value is AtomRef. For the residue, the return
4206 * value is a String. Otherwise, the return value is an Array of Integers.
4209 s_MolEnumerable_Aref(VALUE self, VALUE arg1)
4211 MolEnumerable *mseq;
4214 Data_Get_Struct(self, MolEnumerable, mseq);
4216 if (mseq->kind == kAtomKind) {
4217 return ValueFromMoleculeAndIndex(mol, s_Molecule_AtomIndexFromValue(mol, arg1));
4219 idx1 = NUM2INT(arg1);
4220 switch (mseq->kind) {
4222 idx2 = (idx1 >= 0 ? idx1 : mol->nbonds + idx1);
4223 if (idx2 < 0 || idx2 >= mol->nbonds)
4224 rb_raise(rb_eIndexError, "bond index out of range (%d; should be %d..%d)", idx1, -mol->nbonds, mol->nbonds - 1);
4225 return rb_ary_new3(2, INT2NUM(mol->bonds[idx2 * 2]), INT2NUM(mol->bonds[idx2 * 2 + 1]));
4228 idx2 = (idx1 >= 0 ? idx1 : mol->nangles + idx1);
4229 if (idx2 < 0 || idx2 >= mol->nangles)
4230 rb_raise(rb_eIndexError, "angle index out of range (%d; should be %d..%d)", idx1, -mol->nangles, mol->nangles - 1);
4231 return rb_ary_new3(3, INT2NUM(mol->angles[idx2 * 3]), INT2NUM(mol->angles[idx2 * 3 + 1]), INT2NUM(mol->angles[idx2 * 3 + 2]));
4233 case kDihedralKind: {
4234 idx2 = (idx1 >= 0 ? idx1 : mol->ndihedrals + idx1);
4235 if (idx2 < 0 || idx2 >= mol->ndihedrals)
4236 rb_raise(rb_eIndexError, "dihedral index out of range (%d; should be %d..%d)", idx1, -mol->ndihedrals, mol->ndihedrals - 1);
4237 return rb_ary_new3(4, INT2NUM(mol->dihedrals[idx2 * 4]), INT2NUM(mol->dihedrals[idx2 * 4 + 1]), INT2NUM(mol->dihedrals[idx2 * 4 + 2]), INT2NUM(mol->dihedrals[idx2 * 4 + 3]));
4239 case kImproperKind: {
4240 idx2 = (idx1 >= 0 ? idx1 : mol->nimpropers + idx1);
4241 if (idx2 < 0 || idx2 >= mol->nimpropers)
4242 rb_raise(rb_eIndexError, "improper index out of range (%d; should be %d..%d)", idx1, -mol->nimpropers, mol->nimpropers - 1);
4243 return rb_ary_new3(4, INT2NUM(mol->impropers[idx2 * 4]), INT2NUM(mol->impropers[idx2 * 4 + 1]), INT2NUM(mol->impropers[idx2 * 4 + 2]), INT2NUM(mol->impropers[idx2 * 4 + 3]));
4245 case kResidueKind: {
4247 idx2 = (idx1 >= 0 ? idx1 : mol->nresidues + idx1);
4248 if (idx2 < 0 || idx2 >= mol->nresidues)
4249 rb_raise(rb_eIndexError, "residue index out of range (%d; should be %d..%d)", idx1, -mol->nresidues, mol->nresidues - 1);
4250 p = mol->residues[idx2];
4251 return rb_str_new(p, strlen_limit(p, 4));
4261 * Returns the number of objects included in this enumerable.
4264 s_MolEnumerable_Length(VALUE self)
4266 MolEnumerable *mseq;
4267 Data_Get_Struct(self, MolEnumerable, mseq);
4268 switch (mseq->kind) {
4270 return INT2NUM(mseq->mol->natoms);
4272 return INT2NUM(mseq->mol->nbonds);
4274 return INT2NUM(mseq->mol->nangles);
4276 return INT2NUM(mseq->mol->ndihedrals);
4278 return INT2NUM(mseq->mol->nimpropers);
4280 return INT2NUM(mseq->mol->nresidues);
4289 * Call the block for each atom/bond/angle/dihedral/improper/residue. The block argument is
4290 * an AtomRef for atoms, a String for residues, and an Array of Integers for others.
4291 * For the atoms, a same AtomRef object is passed (with different internal information)
4292 * for each invocation of block. Otherwise, a new Ruby object will be created and passed
4293 * for each iteration.
4296 s_MolEnumerable_Each(VALUE self)
4298 MolEnumerable *mseq;
4300 int len = NUM2INT(s_MolEnumerable_Length(self));
4301 Data_Get_Struct(self, MolEnumerable, mseq);
4302 if (mseq->kind == kAtomKind) {
4303 /* The same AtomRef object will be used during the loop */
4304 AtomRef *aref = AtomRefNew(mseq->mol, 0);
4305 VALUE arval = Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
4306 for (i = 0; i < len; i++) {
4311 /* A new ruby object will be created at each iteration (not very efficient) */
4312 for (i = 0; i < len; i++) {
4313 rb_yield(s_MolEnumerable_Aref(self, INT2NUM(i)));
4321 * self == molEnumerable -> boolean
4323 * True if the two arguments point to the same molecule and enumerable type.
4326 s_MolEnumerable_Equal(VALUE self, VALUE val)
4328 if (rb_obj_is_kind_of(val, rb_cMolEnumerable)) {
4329 MolEnumerable *mseq1, *mseq2;
4330 Data_Get_Struct(self, MolEnumerable, mseq1);
4331 Data_Get_Struct(val, MolEnumerable, mseq2);
4332 return ((mseq1->mol == mseq2->mol && mseq1->kind == mseq2->kind) ? Qtrue : Qfalse);
4333 } else return Qfalse;
4337 #pragma mark ====== Molecule Class ======
4339 /* An malloc'ed string buffer. Retains the error/warning message from the last ***load/***save method. */
4340 /* Accessible from Ruby as Molecule#error_message and Molecule#error_message=. */
4341 char *gLoadSaveErrorMessage = NULL;
4343 #define MoleculeClearLoadSaveErrorMessage() (gLoadSaveErrorMessage != NULL ? (free(gLoadSaveErrorMessage), gLoadSaveErrorMessage = NULL) : NULL)
4346 MoleculeFromValue(VALUE val)
4349 if (!rb_obj_is_kind_of(val, rb_cMolecule))
4350 rb_raise(rb_eMolbyError, "Molecule instance is expected");
4351 Data_Get_Struct(val, Molecule, mol);
4355 static VALUE sMoleculeRetainArray = Qnil;
4357 /* The function is called from MoleculeRelease() */
4358 /* The Ruby Molecule object is held as mol->exmolobj, and is also protected from */
4359 /* GC by registering in the sMoleculeRetainArray. This causes the same Ruby */
4360 /* object is always returned for the same Molecule. */
4361 /* When the reference count of the Molecule becomes 1, then the Ruby object is */
4362 /* removed from sMoleculeRetainArray. In this situation, the Molecule is retained */
4363 /* only by the currently alive Ruby containers. When the Ruby Molecule object is */
4364 /* removed from all alive Ruby containers, the Ruby object will be collected by */
4365 /* the next GC invocation, and at that time the Molecule structure is properly released. */
4367 /* Register/unregister the exmolobj Ruby object */
4369 MoleculeReleaseExternalObj(Molecule *mol)
4371 if (mol != NULL && mol->base.refCount <= 2 && mol->exmolobjProtected == 1) {
4372 rb_ary_delete(sMoleculeRetainArray, (VALUE)mol->exmolobj);
4373 mol->exmolobjProtected = 0;
4378 MoleculeRetainExternalObj(Molecule *mol)
4380 if (mol != NULL && mol->base.refCount >= 2 && mol->exmolobj != NULL && mol->exmolobjProtected == 0) {
4381 if (sMoleculeRetainArray == Qnil) {
4382 rb_define_readonly_variable("molecules", &sMoleculeRetainArray);
4383 sMoleculeRetainArray = rb_ary_new();
4386 rb_ary_push(sMoleculeRetainArray, (VALUE)mol->exmolobj);
4387 mol->exmolobjProtected = 1;
4391 /* Release hook function for Ruby */
4393 MoleculeReleaseHook(Molecule *mol)
4395 if (mol->exmolobj != NULL) {
4396 /* No need to remove from sMoleculeRetainArray */
4397 mol->exmolobj = NULL;
4398 mol->exmolobjProtected = 0;
4400 MoleculeRelease(mol);
4404 ValueFromMolecule(Molecule *mol)
4408 if (mol->exmolobj != NULL)
4409 return (VALUE)mol->exmolobj;
4410 mol->exmolobj = (void *)Data_Wrap_Struct(rb_cMolecule, 0, (void (*)(void *))MoleculeReleaseHook, mol);
4411 MoleculeRetain(mol); /* MoleculeRetainExternalObj() is automatically called */
4412 return (VALUE)mol->exmolobj;
4417 s_Molecule_Alloc(VALUE klass)
4420 Molecule *mol = MoleculeNew();
4421 val = ValueFromMolecule(mol);
4422 MoleculeRelease(mol); /* Only the returned Ruby object retains this molecule */
4427 s_Molecule_AtomIndexFromValue(Molecule *mol, VALUE val)
4431 if (FIXNUM_P(val)) {
4433 if (n >= 0 && n < mol->natoms)
4435 n = -1; /* No such atom */
4436 val = rb_inspect(val);
4438 n = MoleculeAtomIndexFromString(mol, StringValuePtr(val));
4440 if (n >= 0 && n < mol->natoms)
4443 rb_raise(rb_eMolbyError, "no such atom: %s", p);
4445 rb_raise(rb_eMolbyError, "bad format of atom specification: %s", p);
4447 rb_raise(rb_eMolbyError, "error in converting value to atom index: %s", p);
4448 return 0; /* Not reached */
4452 s_Molecule_AtomGroupFromValue(VALUE self, VALUE val)
4455 val = rb_funcall(self, rb_intern("atom_group"), 1, val);
4456 if (!rb_obj_is_kind_of(val, rb_cIntGroup))
4457 rb_raise(rb_eMolbyError, "IntGroup instance is expected");
4458 Data_Get_Struct(val, IntGroup, ig);
4464 s_Molecule_RaiseOnLoadSave(int status, const char *msg, const char *fname)
4466 if (gLoadSaveErrorMessage != NULL) {
4467 MyAppCallback_setConsoleColor(1);
4468 MyAppCallback_showScriptMessage("On loading %s:\n%s\n", fname, gLoadSaveErrorMessage);
4469 MyAppCallback_setConsoleColor(0);
4472 rb_raise(rb_eMolbyError, "%s %s", msg, fname);
4479 * Duplicate a molecule. All entries are deep copied, so modifying the newly
4480 * created object does not affect the old object in any sense.
4483 s_Molecule_InitCopy(VALUE self, VALUE arg)
4485 Molecule *mp1, *mp2;
4486 Data_Get_Struct(self, Molecule, mp1);
4487 mp2 = MoleculeFromValue(arg);
4488 if (MoleculeInitWithMolecule(mp1, mp2) == NULL)
4489 rb_raise(rb_eMolbyError, "Cannot duplicate molecule");
4495 * loadmbsf(file) -> bool
4497 * Read a structure from a mbsf file.
4498 * Return true if successful.
4501 s_Molecule_Loadmbsf(int argc, VALUE *argv, VALUE self)
4507 MoleculeClearLoadSaveErrorMessage();
4508 Data_Get_Struct(self, Molecule, mol);
4509 rb_scan_args(argc, argv, "1", &fname);
4510 fstr = FileStringValuePtr(fname);
4511 retval = MoleculeLoadMbsfFile(mol, fstr, &gLoadSaveErrorMessage);
4512 s_Molecule_RaiseOnLoadSave(retval, "Failed to load mbsf", fstr);
4518 * loadpsf(file, pdbfile = nil) -> bool
4520 * Read a structure from a psf file. molecule must be empty. The psf may be
4521 * an "extended" version, which also contains coordinates. If pdbfile
4522 * is given, then atomic coordinates are read from that file.
4523 * Return true if successful.
4526 s_Molecule_Loadpsf(int argc, VALUE *argv, VALUE self)
4528 VALUE fname, pdbname;
4529 char *fstr, *pdbstr;
4532 Data_Get_Struct(self, Molecule, mol);
4533 if (mol->natoms > 0)
4534 return Qnil; /* Must be a new molecule */
4535 MoleculeClearLoadSaveErrorMessage();
4536 rb_scan_args(argc, argv, "11", &fname, &pdbname);
4537 fstr = FileStringValuePtr(fname);
4538 retval = MoleculeLoadPsfFile(mol, fstr, &gLoadSaveErrorMessage);
4539 s_Molecule_RaiseOnLoadSave(retval, "Failed to load psf", fstr);
4541 if (!NIL_P(pdbname)) {
4542 pdbstr = strdup(FileStringValuePtr(pdbname));
4543 retval = MoleculeReadCoordinatesFromPdbFile(mol, pdbstr, &gLoadSaveErrorMessage);
4545 s_Molecule_RaiseOnLoadSave(retval, "Failed to load coordinates from pdb", pdbstr);
4552 * loadpdb(file) -> bool
4554 * Read coordinates from a pdb file. If molecule is empty, then structure is build
4555 * by use of CONECT instructions. Otherwise, only the coordinates are read in.
4556 * Return true if successful.
4559 s_Molecule_Loadpdb(int argc, VALUE *argv, VALUE self)
4565 Data_Get_Struct(self, Molecule, mol);
4566 rb_scan_args(argc, argv, "1", &fname);
4567 MoleculeClearLoadSaveErrorMessage();
4568 fstr = FileStringValuePtr(fname);
4569 retval = MoleculeReadCoordinatesFromPdbFile(mol, fstr, &gLoadSaveErrorMessage);
4570 s_Molecule_RaiseOnLoadSave(retval, "Failed to load pdb", fstr);
4576 * loaddcd(file) -> bool
4578 * Read coordinates from a dcd file. The molecule should not empty.
4579 * Return true if successful.
4582 s_Molecule_Loaddcd(int argc, VALUE *argv, VALUE self)
4588 Data_Get_Struct(self, Molecule, mol);
4589 rb_scan_args(argc, argv, "1", &fname);
4590 MoleculeClearLoadSaveErrorMessage();
4591 fstr = FileStringValuePtr(fname);
4592 retval = MoleculeReadCoordinatesFromDcdFile(mol, fstr, &gLoadSaveErrorMessage);
4593 s_Molecule_RaiseOnLoadSave(retval, "Failed to load dcd", fstr);
4599 * loadtep(file) -> bool
4601 * Read coordinates from an ortep .tep file.
4602 * Return true if successful.
4605 s_Molecule_Loadtep(int argc, VALUE *argv, VALUE self)
4611 Data_Get_Struct(self, Molecule, mol);
4612 rb_scan_args(argc, argv, "1", &fname);
4613 MoleculeClearLoadSaveErrorMessage();
4614 fstr = FileStringValuePtr(fname);
4615 retval = MoleculeLoadTepFile(mol, fstr, &gLoadSaveErrorMessage);
4616 s_Molecule_RaiseOnLoadSave(retval, "Failed to load ORTEP file", fstr);
4622 * loadres(file) -> bool
4624 * Read coordinates from a shelx .res file.
4625 * Return true if successful.
4628 s_Molecule_Loadres(int argc, VALUE *argv, VALUE self)
4634 Data_Get_Struct(self, Molecule, mol);
4635 rb_scan_args(argc, argv, "1", &fname);
4636 MoleculeClearLoadSaveErrorMessage();
4637 fstr = FileStringValuePtr(fname);
4638 retval = MoleculeLoadShelxFile(mol, fstr, &gLoadSaveErrorMessage);
4639 s_Molecule_RaiseOnLoadSave(retval, "Failed to load SHELX res file", fstr);
4645 * loadfchk(file) -> bool
4647 * Read coordinates and MO information from a Gaussian fchk file. (TODO: implement this)
4648 * Return true if successful.
4651 s_Molecule_Loadfchk(int argc, VALUE *argv, VALUE self)
4657 Data_Get_Struct(self, Molecule, mol);
4658 rb_scan_args(argc, argv, "1", &fname);
4659 MoleculeClearLoadSaveErrorMessage();
4660 fstr = FileStringValuePtr(fname);
4661 retval = MoleculeLoadGaussianFchkFile(mol, fstr, &gLoadSaveErrorMessage);
4662 s_Molecule_RaiseOnLoadSave(retval, "Failed to load Gaussian fchk", fstr);
4668 * loaddat(file) -> bool
4670 * Read coordinates and ESP information from a GAMESS dat file. (TODO: read MO info as well)
4671 * Return true if successful.
4674 s_Molecule_Loaddat(int argc, VALUE *argv, VALUE self)
4680 Data_Get_Struct(self, Molecule, mol);
4681 rb_scan_args(argc, argv, "1", &fname);
4682 MoleculeClearLoadSaveErrorMessage();
4683 fstr = FileStringValuePtr(fname);
4684 MyAppCallback_showProgressPanel("Loading GAMESS dat file...");
4685 retval = MoleculeLoadGamessDatFile(mol, fstr, &gLoadSaveErrorMessage);
4686 MyAppCallback_hideProgressPanel();
4687 s_Molecule_RaiseOnLoadSave(retval, "Failed to load GAMESS dat", fstr);
4693 * savembsf(file) -> bool
4695 * Write structure as a mbsf file. Returns true if successful.
4698 s_Molecule_Savembsf(VALUE self, VALUE fname)
4703 Data_Get_Struct(self, Molecule, mol);
4704 MoleculeClearLoadSaveErrorMessage();
4705 fstr = FileStringValuePtr(fname);
4706 retval = MoleculeWriteToMbsfFile(mol, fstr, &gLoadSaveErrorMessage);
4707 s_Molecule_RaiseOnLoadSave(retval, "Failed to save mbsf", fstr);
4713 * savepsf(file) -> bool
4715 * Write structure as a psf file. Returns true if successful.
4718 s_Molecule_Savepsf(VALUE self, VALUE fname)
4723 Data_Get_Struct(self, Molecule, mol);
4724 MoleculeClearLoadSaveErrorMessage();
4725 fstr = FileStringValuePtr(fname);
4726 retval = MoleculeWriteToPsfFile(mol, fstr, &gLoadSaveErrorMessage);
4727 s_Molecule_RaiseOnLoadSave(retval, "Failed to save psf", fstr);
4733 * savepdb(file) -> bool
4735 * Write coordinates as a pdb file. Returns true if successful.
4738 s_Molecule_Savepdb(VALUE self, VALUE fname)
4743 Data_Get_Struct(self, Molecule, mol);
4744 MoleculeClearLoadSaveErrorMessage();
4745 fstr = FileStringValuePtr(fname);
4746 retval = MoleculeWriteToPdbFile(mol, fstr, &gLoadSaveErrorMessage);
4747 s_Molecule_RaiseOnLoadSave(retval, "Failed to save pdb", fstr);
4753 * savedcd(file) -> bool
4755 * Write coordinates as a dcd file. Returns true if successful.
4758 s_Molecule_Savedcd(VALUE self, VALUE fname)
4763 Data_Get_Struct(self, Molecule, mol);
4764 MoleculeClearLoadSaveErrorMessage();
4765 fstr = FileStringValuePtr(fname);
4766 retval = MoleculeWriteToDcdFile(mol, fstr, &gLoadSaveErrorMessage);
4767 s_Molecule_RaiseOnLoadSave(retval, "Failed to save dcd", fstr);
4773 * savetep(file) -> bool
4775 * Write coordinates as an ORTEP file. Returns true if successful.
4779 s_Molecule_Savetep(VALUE self, VALUE fname)
4784 Data_Get_Struct(self, Molecule, mol);
4785 fstr = FileStringValuePtr(fname);
4786 if (MoleculeWriteToTepFile(mol, fstr, errbuf, sizeof errbuf) != 0)
4787 rb_raise(rb_eMolbyError, errbuf);
4792 /* load([ftype, ] fname, ...) */
4794 s_Molecule_LoadSave(int argc, VALUE *argv, VALUE self, int loadFlag)
4797 char *argstr, *methname, *p, *type = "";
4800 const char *ls = (loadFlag ? "load" : "save");
4801 int lslen = strlen(ls);
4806 if (argc == 0 || (argstr = StringValuePtr(argv[0])) == NULL)
4807 rb_raise(rb_eMolbyError, "the first argument must be either filename or \":filetype\"");
4808 if (argstr[0] == ':') {
4809 /* Call "loadXXX" (or "saveXXX") for type ":XXX" */
4810 methname = ALLOC_N(char, lslen + strlen(argstr));
4811 strcpy(methname, ls);
4812 strcat(methname, argstr + 1);
4814 for (i = lslen; methname[i] != 0; i++)
4815 methname[i] = tolower(methname[i]);
4816 mid = rb_intern(methname);
4820 rval = rb_funcall2(self, mid, argc, argv);
4826 /* Guess file type from extension */
4827 p = strrchr(argstr, '.');
4831 for (methname = p; *methname != 0; methname++) {
4832 if (!isalpha(*methname))
4835 if (*methname == 0) {
4836 methname = ALLOC_N(char, lslen + strlen(p) + 1);
4837 if (methname == NULL)
4838 rb_raise(rb_eMolbyError, "Low memory");
4839 strcpy(methname, ls);
4840 strcat(methname, p);
4841 for (i = lslen; methname[i] != 0; i++)
4842 methname[i] = tolower(methname[i]);
4843 mid = rb_intern(methname);
4846 if (rb_respond_to(self, mid)) {
4847 /* Load: try to call the load procedure only if it is available */
4848 rval = rb_funcall2(self, mid, argc, argv);
4853 /* Save: call the save procedure, and if not found then call 'method_missing' */
4854 rval = rb_funcall2(self, mid, argc, argv);
4861 rval = rb_str_to_str(argv[0]);
4862 asprintf(&p, "Failed to %s file %s", (loadFlag ? "load" : "save"), type);
4863 s_Molecule_RaiseOnLoadSave(1, p, StringValuePtr(rval));
4864 return Qnil; /* Does not reach here */
4868 /* Register the path */
4871 Data_Get_Struct(self, Molecule, mol);
4872 MoleculeSetPath(mol, StringValuePtr(argv[0]));
4874 /* Check if all occupancy factors are zero; if that is the case, then all set to 1.0 */
4875 /* for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
4876 if (ap->occupancy != 0.0)
4879 if (i == mol->natoms) {
4880 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
4881 ap->occupancy = 1.0;
4890 * molload(file, *args) -> bool
4892 * Read a structure from the given file by calling the public method "loadXXX" (XXX is the
4893 * file type given by the extension). If this method fails, then all defined (public)
4894 * "loadXXX" methods are invoked, and raises an exception if none of them were successful.
4897 s_Molecule_Load(int argc, VALUE *argv, VALUE self)
4899 return s_Molecule_LoadSave(argc, argv, self, 1);
4904 * molsave(file, *args) -> bool
4906 * Write a structure/coordinate to the given file by calling the public method "saveXXX"
4907 * (XXX is the file type given by the extension).
4910 s_Molecule_Save(int argc, VALUE *argv, VALUE self)
4912 return s_Molecule_LoadSave(argc, argv, self, 0);
4919 * Returns the display name of the molecule. If the molecule has no associated
4920 * document, then returns nil.
4923 s_Molecule_Name(VALUE self)
4927 Data_Get_Struct(self, Molecule, mol);
4928 MoleculeCallback_displayName(mol, buf, sizeof buf);
4932 return rb_str_new2(buf);
4937 * set_name(string) -> self
4939 * Set the name of an untitled molecule. If the molecule is not associated with window
4940 * or it already has an associated file, then exception is thrown.
4943 s_Molecule_SetName(VALUE self, VALUE nval)
4946 Data_Get_Struct(self, Molecule, mol);
4947 if (MoleculeCallback_setDisplayName(mol, StringValuePtr(nval)))
4948 rb_raise(rb_eMolbyError, "Cannot change the window title");
4957 * Returns the full path name of the molecule, if it is associated with a file.
4958 * If the molecule has no associated file, then returns nil.
4961 s_Molecule_Path(VALUE self)
4965 Data_Get_Struct(self, Molecule, mol);
4966 MoleculeCallback_pathName(mol, buf, sizeof buf);
4970 return Ruby_NewFileStringValue(buf);
4977 * Returns the full path name of the directory in which the file associated with the
4978 * molecule is located. If the molecule has no associated file, then returns nil.
4981 s_Molecule_Dir(VALUE self)
4985 Data_Get_Struct(self, Molecule, mol);
4986 MoleculeCallback_pathName(mol, buf, sizeof buf);
4988 translate_char(buf, '\\', '/');
4993 p = strrchr(buf, '/');
4996 return rb_str_new2(buf);
5004 * Returns a string in the form "Molecule[name]" if the molecule has the associated
5005 * document. Otherwise, a string "<Molecule:0x****>" (the address is the address of
5006 * the Molecule structure) is returned.
5009 s_Molecule_Inspect(VALUE self)
5013 Data_Get_Struct(self, Molecule, mol);
5014 MoleculeCallback_displayName(mol, buf, sizeof buf);
5016 /* No associated document */
5017 snprintf(buf, sizeof buf, "#<Molecule:0x%lx>", self);
5018 return rb_str_new2(buf);
5020 /* Check whether the document name is duplicate */
5024 for (idx = 0, k = k2 = 0; (mol2 = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
5025 MoleculeCallback_displayName(mol2, buf2, sizeof buf2);
5026 if (strcmp(buf, buf2) == 0) {
5033 snprintf(buf2, sizeof buf2, "Molecule[\"%s\",%d]", buf, k2);
5035 snprintf(buf2, sizeof buf2, "Molecule[\"%s\"]", buf);
5037 return rb_str_new2(buf2);
5044 * open(file) -> Molecule
5046 * Create a new molecule from file as a document. If file is not given, an untitled document is created.
5049 s_Molecule_Open(int argc, VALUE *argv, VALUE self)
5055 rb_scan_args(argc, argv, "01", &fname);
5059 p = FileStringValuePtr(fname);
5060 iflag = Ruby_SetInterruptFlag(Qfalse);
5061 mp = MoleculeCallback_openNewMolecule(p);
5062 Ruby_SetInterruptFlag(iflag);
5065 rb_raise(rb_eMolbyError, "Cannot create untitled document");
5067 rb_raise(rb_eMolbyError, "Cannot open the file %s", p);
5069 return ValueFromMolecule(mp);
5075 * new(file, *args) -> Molecule
5077 * Create a new molecule and call "load" method with the same arguments.
5080 s_Molecule_Initialize(int argc, VALUE *argv, VALUE self)
5083 return s_Molecule_Load(argc, argv, self);
5084 else return Qnil; /* An empty molecule (which is prepared in s_Molecule_Alloc()) is returned */
5088 s_Molecule_MolEnumerable(VALUE self, int kind)
5091 MolEnumerable *mseq;
5092 Data_Get_Struct(self, Molecule, mol);
5093 mseq = MolEnumerableNew(mol, kind);
5094 return Data_Wrap_Struct(rb_cMolEnumerable, 0, (void (*)(void *))MolEnumerableRelease, mseq);
5099 * atoms -> MolEnumerable
5101 * Returns a MolEnumerable object representing the array of atoms.
5104 s_Molecule_Atoms(VALUE self)
5106 return s_Molecule_MolEnumerable(self, kAtomKind);
5111 * bonds -> MolEnumerable
5113 * Returns a MolEnumerable object representing the array of bonds. A bond is represented
5114 * by an array of two atom indices.
5117 s_Molecule_Bonds(VALUE self)
5119 return s_Molecule_MolEnumerable(self, kBondKind);
5124 * angles -> MolEnumerable
5126 * Returns a MolEnumerable object representing the array of angles. An angle is represented
5127 * by an array of three atom indices.
5130 s_Molecule_Angles(VALUE self)
5132 return s_Molecule_MolEnumerable(self, kAngleKind);
5137 * dihedrals -> MolEnumerable
5139 * Returns a MolEnumerable object representing the array of dihedrals. A dihedral is represented
5140 * by an array of four atom indices.
5143 s_Molecule_Dihedrals(VALUE self)
5145 return s_Molecule_MolEnumerable(self, kDihedralKind);
5150 * impropers -> MolEnumerable
5152 * Returns a MolEnumerable object representing the array of impropers. An improper is represented
5153 * by an array of four atom indices.
5156 s_Molecule_Impropers(VALUE self)
5158 return s_Molecule_MolEnumerable(self, kImproperKind);
5163 * residues -> MolEnumerable
5165 * Returns a MolEnumerable object representing the array of residue names.
5168 s_Molecule_Residues(VALUE self)
5170 return s_Molecule_MolEnumerable(self, kResidueKind);
5177 * Returns the number of atoms.
5180 s_Molecule_Natoms(VALUE self)
5183 Data_Get_Struct(self, Molecule, mol);
5184 return INT2NUM(mol->natoms);
5191 * Returns the number of bonds.
5194 s_Molecule_Nbonds(VALUE self)
5197 Data_Get_Struct(self, Molecule, mol);
5198 return INT2NUM(mol->nbonds);
5203 * nangles -> Integer
5205 * Returns the number of angles.
5208 s_Molecule_Nangles(VALUE self)
5211 Data_Get_Struct(self, Molecule, mol);
5212 return INT2NUM(mol->nangles);
5217 * ndihedrals -> Integer
5219 * Returns the number of dihedrals.
5222 s_Molecule_Ndihedrals(VALUE self)
5225 Data_Get_Struct(self, Molecule, mol);
5226 return INT2NUM(mol->ndihedrals);
5231 * nimpropers -> Integer
5233 * Returns the number of impropers.
5236 s_Molecule_Nimpropers(VALUE self)
5239 Data_Get_Struct(self, Molecule, mol);
5240 return INT2NUM(mol->nimpropers);
5245 * nresidues -> Integer
5247 * Returns the number of residues.
5250 s_Molecule_Nresidues(VALUE self)
5253 Data_Get_Struct(self, Molecule, mol);
5254 return INT2NUM(mol->nresidues);
5258 s_Molecule_BondParIsObsolete(VALUE self, VALUE val)
5260 rb_raise(rb_eMolbyError, "Molecule#bond_par, angle_par, dihedral_par, improper_par, vdw_par are now obsolete. You can use MDArena#bond_par, angle_par, dihedral_par, improper_par, vdw_par instead, and probably these are what you really want.");
5265 * bond_par(idx) -> ParameterRef
5267 * Returns the MD parameter for the idx-th bond.
5271 s_Molecule_BondPar(VALUE self, VALUE val)
5278 Data_Get_Struct(self, Molecule, mol);
5279 ival = NUM2INT(rb_Integer(val));
5280 if (ival < -mol->nbonds || ival >= mol->nbonds)
5281 rb_raise(rb_eMolbyError, "bond index (%d) out of range", ival);
5283 ival += mol->nbonds;
5284 s_RebuildMDParameterIfNecessary(self, Qtrue);
5285 i1 = mol->bonds[ival * 2];
5286 i2 = mol->bonds[ival * 2 + 1];
5287 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5288 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5289 bp = ParameterLookupBondPar(mol->par, t1, t2, i1, i2, 0);
5292 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kBondParType, bp - mol->par->bondPars);
5298 * angle_par(idx) -> ParameterRef
5300 * Returns the MD parameter for the idx-th angle.
5304 s_Molecule_AnglePar(VALUE self, VALUE val)
5311 Data_Get_Struct(self, Molecule, mol);
5312 ival = NUM2INT(rb_Integer(val));
5313 if (ival < -mol->nangles || ival >= mol->nangles)
5314 rb_raise(rb_eMolbyError, "angle index (%d) out of range", ival);
5316 ival += mol->nangles;
5317 s_RebuildMDParameterIfNecessary(self, Qtrue);
5318 i1 = mol->angles[ival * 3];
5319 i2 = mol->angles[ival * 3 + 1];
5320 i3 = mol->angles[ival * 3 + 2];
5321 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5322 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5323 t3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
5324 ap = ParameterLookupAnglePar(mol->par, t1, t2, t3, i1, i2, i3, 0);
5327 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kAngleParType, ap - mol->par->anglePars);
5332 * dihedral_par(idx) -> ParameterRef
5334 * Returns the MD parameter for the idx-th dihedral.
5338 s_Molecule_DihedralPar(VALUE self, VALUE val)
5343 UInt t1, t2, t3, t4;
5345 Data_Get_Struct(self, Molecule, mol);
5346 ival = NUM2INT(rb_Integer(val));
5347 if (ival < -mol->ndihedrals || ival >= mol->ndihedrals)
5348 rb_raise(rb_eMolbyError, "dihedral index (%d) out of range", ival);
5350 ival += mol->ndihedrals;
5351 s_RebuildMDParameterIfNecessary(self, Qtrue);
5352 i1 = mol->dihedrals[ival * 4];
5353 i2 = mol->dihedrals[ival * 4 + 1];
5354 i3 = mol->dihedrals[ival * 4 + 2];
5355 i4 = mol->dihedrals[ival * 4 + 3];
5356 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5357 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5358 t3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
5359 t4 = ATOM_AT_INDEX(mol->atoms, i4)->type;
5360 tp = ParameterLookupDihedralPar(mol->par, t1, t2, t3, t4, i1, i2, i3, i4, 0);
5363 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kDihedralParType, tp - mol->par->dihedralPars);
5368 * improper_par(idx) -> ParameterRef
5370 * Returns the MD parameter for the idx-th improper.
5374 s_Molecule_ImproperPar(VALUE self, VALUE val)
5379 UInt t1, t2, t3, t4;
5381 Data_Get_Struct(self, Molecule, mol);
5382 ival = NUM2INT(rb_Integer(val));
5383 if (ival < -mol->nimpropers || ival >= mol->nimpropers)
5384 rb_raise(rb_eMolbyError, "improper index (%d) out of range", ival);
5386 ival += mol->nimpropers;
5387 s_RebuildMDParameterIfNecessary(self, Qtrue);
5388 i1 = mol->impropers[ival * 4];
5389 i2 = mol->impropers[ival * 4 + 1];
5390 i3 = mol->impropers[ival * 4 + 2];
5391 i4 = mol->impropers[ival * 4 + 3];
5392 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5393 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5394 t3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
5395 t4 = ATOM_AT_INDEX(mol->atoms, i4)->type;
5396 tp = ParameterLookupImproperPar(mol->par, t1, t2, t3, t4, i1, i2, i3, i4, 0);
5399 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kImproperParType, tp - mol->par->improperPars);
5404 * vdw_par(idx) -> ParameterRef
5406 * Returns the vdw parameter for the idx-th atom.
5410 s_Molecule_VdwPar(VALUE self, VALUE val)
5416 Data_Get_Struct(self, Molecule, mol);
5417 ival = NUM2INT(rb_Integer(val));
5418 if (ival < -mol->natoms || ival >= mol->natoms)
5419 rb_raise(rb_eMolbyError, "atom index (%d) out of range", ival);
5421 ival += mol->natoms;
5422 s_RebuildMDParameterIfNecessary(self, Qtrue);
5423 t1 = ATOM_AT_INDEX(mol->atoms, ival)->type;
5424 vp = ParameterLookupVdwPar(mol->par, t1, 0);
5427 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwParType, vp - mol->par->vdwPars);
5433 * start_step -> Integer
5435 * Returns the start step (defined by dcd format).
5438 s_Molecule_StartStep(VALUE self)
5441 Data_Get_Struct(self, Molecule, mol);
5442 return INT2NUM(mol->startStep);
5447 * start_step = Integer
5449 * Set the start step (defined by dcd format).
5452 s_Molecule_SetStartStep(VALUE self, VALUE val)
5455 Data_Get_Struct(self, Molecule, mol);
5456 mol->startStep = NUM2INT(rb_Integer(val));
5462 * steps_per_frame -> Integer
5464 * Returns the number of steps between frames (defined by dcd format).
5467 s_Molecule_StepsPerFrame(VALUE self)
5470 Data_Get_Struct(self, Molecule, mol);
5471 return INT2NUM(mol->stepsPerFrame);
5476 * steps_per_frame = Integer
5478 * Set the number of steps between frames (defined by dcd format).
5481 s_Molecule_SetStepsPerFrame(VALUE self, VALUE val)
5484 Data_Get_Struct(self, Molecule, mol);
5485 mol->stepsPerFrame = NUM2INT(rb_Integer(val));
5491 * ps_per_step -> Float
5493 * Returns the time increment (in picoseconds) for one step (defined by dcd format).
5496 s_Molecule_PsPerStep(VALUE self)
5499 Data_Get_Struct(self, Molecule, mol);
5500 return rb_float_new(mol->psPerStep);
5505 * ps_per_step = Float
5507 * Set the time increment (in picoseconds) for one step (defined by dcd format).
5510 s_Molecule_SetPsPerStep(VALUE self, VALUE val)
5513 Data_Get_Struct(self, Molecule, mol);
5514 mol->psPerStep = NUM2DBL(rb_Float(val));
5520 * find_angles -> Integer
5522 * Find the angles from the bonds. Returns the number of angles newly created.
5526 s_Molecule_FindAngles(VALUE self)
5532 Data_Get_Struct(self, Molecule, mol);
5533 if (mol == NULL || mol->natoms == 0)
5537 for (n1 = 0, ap = mol->atoms; n1 < mol->natoms; n1++, ap = ATOM_NEXT(ap)) {
5538 nc = ap->connect.count;
5540 for (i = 0; i < nc; i++) {
5541 n[0] = ap->connects[i];
5542 for (j = i + 1; j < nc; j++) {
5543 n[2] = ap->connects[j];
5544 if (MoleculeLookupAngle(mol, n[0], n[1], n[2]) < 0)
5545 AssignArray(&ip, &nip, sizeof(Int) * 3, nip, n);
5550 MolActionCreateAndPerform(mol, gMolActionAddAngles, nip * 3, ip, NULL);
5553 return INT2NUM(nip);
5558 * find_dihedrals -> Integer
5560 * Find the dihedrals from the bonds. Returns the number of dihedrals newly created.
5564 s_Molecule_FindDihedrals(VALUE self)
5568 int n1, i, j, k, nc1, nc2;
5570 Data_Get_Struct(self, Molecule, mol);
5571 if (mol == NULL || mol->natoms == 0)
5575 for (n1 = 0, ap1 = mol->atoms; n1 < mol->natoms; n1++, ap1 = ATOM_NEXT(ap1)) {
5576 nc1 = ap1->connect.count;
5578 for (i = 0; i < nc1; i++) {
5579 n[2] = ap1->connects[i];
5582 ap2 = ATOM_AT_INDEX(mol->atoms, n[2]);
5583 nc2 = ap2->connect.count;
5584 for (j = 0; j < nc1; j++) {
5585 n[0] = ap1->connects[j];
5588 for (k = 0; k < nc2; k++) {
5589 n[3] = ap2->connects[k];
5590 if (n[3] == n1 || n[3] == n[0])
5592 if (MoleculeLookupDihedral(mol, n[0], n[1], n[2], n[3]) < 0)
5593 AssignArray(&ip, &nip, sizeof(Int) * 4, nip, n);
5599 MolActionCreateAndPerform(mol, gMolActionAddDihedrals, nip * 4, ip, NULL);
5602 return INT2NUM(nip);
5608 * nresidues = Integer
5610 * Change the number of residues.
5613 s_Molecule_ChangeNresidues(VALUE self, VALUE val)
5616 int ival = NUM2INT(val);
5617 Data_Get_Struct(self, Molecule, mol);
5618 MolActionCreateAndPerform(mol, gMolActionChangeNumberOfResidues, ival);
5619 if (ival != mol->nresidues)
5620 rb_raise(rb_eMolbyError, "Cannot set the number of residues to %d (set to %d)", ival, mol->nresidues);
5626 * max_residue_number(atom_group = nil) -> Integer
5628 * Returns the maximum residue number actually used. If an atom group is given, only
5629 * these atoms are examined. If no atom is present, nil is returned.
5632 s_Molecule_MaxResSeq(int argc, VALUE *argv, VALUE self)
5638 Data_Get_Struct(self, Molecule, mol);
5639 rb_scan_args(argc, argv, "01", &gval);
5640 ig = (gval == Qnil ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
5641 maxSeq = MoleculeMaximumResidueNumber(mol, ig);
5642 return (maxSeq >= 0 ? INT2NUM(maxSeq) : Qnil);
5647 * min_residue_number(atom_group = nil) -> Integer
5649 * Returns the minimum residue number actually used. If an atom group is given, only
5650 * these atoms are examined. If no atom is present, nil is returned.
5653 s_Molecule_MinResSeq(int argc, VALUE *argv, VALUE self)
5659 Data_Get_Struct(self, Molecule, mol);
5660 rb_scan_args(argc, argv, "01", &gval);
5661 ig = (gval == Qnil ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
5662 minSeq = MoleculeMinimumResidueNumber(mol, ig);
5663 return (minSeq >= 0 ? INT2NUM(minSeq) : Qnil);
5668 * each_atom(atom_group = nil) {|aref| ...}
5670 * Execute the block, with the AtomRef object for each atom as the argument. If an atom
5671 * group is given, only these atoms are processed.
5672 * If atom_group is nil, this is equivalent to self.atoms.each, except that the return value
5673 * is self (a Molecule object).
5676 s_Molecule_EachAtom(int argc, VALUE *argv, VALUE self)
5684 Data_Get_Struct(self, Molecule, mol);
5685 rb_scan_args(argc, argv, "01", &gval);
5686 ig = (gval == Qnil ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
5687 arval = ValueFromMoleculeAndIndex(mol, 0);
5688 Data_Get_Struct(arval, AtomRef, aref);
5689 for (i = 0; i < mol->natoms; i++) {
5691 if (ig == NULL || IntGroupLookup(ig, i, NULL))
5695 IntGroupRelease(ig);
5701 * cell -> [a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]]
5703 * Returns the unit cell parameters. If cell is not set, returns nil.
5706 s_Molecule_Cell(VALUE self)
5711 Data_Get_Struct(self, Molecule, mol);
5712 if (mol->cell == NULL)
5714 val = rb_ary_new2(6);
5715 for (i = 0; i < 6; i++)
5716 rb_ary_push(val, rb_float_new(mol->cell->cell[i]));
5717 if (mol->cell->has_sigma) {
5718 for (i = 0; i < 6; i++) {
5719 rb_ary_push(val, rb_float_new(mol->cell->cellsigma[i]));
5727 * cell = [a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]]
5728 * set_cell([a, b, c, alpha, beta, gamma[, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]], convert_coord = nil)
5730 * Set the unit cell parameters. If the cell value is nil, then clear the current cell.
5731 If the given argument has 12 or more members, then the second half of the parameters represents the sigma values.
5732 This operation is undoable.
5733 Convert_coord is a flag to specify that the coordinates should be transformed so that the fractional coordinates remain the same.
5736 s_Molecule_SetCell(int argc, VALUE *argv, VALUE self)
5740 int i, convert_coord, n;
5742 Data_Get_Struct(self, Molecule, mol);
5743 rb_scan_args(argc, argv, "11", &val, &cval);
5748 val = rb_ary_to_ary(val);
5749 len = RARRAY_LEN(val);
5752 } else if (len >= 6) {
5754 } else rb_raise(rb_eMolbyError, "too few members for cell parameters (6 or 12 required)");
5755 for (i = 0; i < n; i++)
5756 d[i] = NUM2DBL(rb_Float((RARRAY_PTR(val))[i]));
5758 convert_coord = (RTEST(cval) ? 1 : 0);
5759 MolActionCreateAndPerform(mol, gMolActionSetCell, n, d, convert_coord);
5765 * box -> [avec, bvec, cvec, origin, flags]
5767 * Get the unit cell information in the form of a periodic bounding box.
5768 * Avec, bvec, cvec, origin are Vector3D objects, and flags is a 3-member array of
5769 * Integers which define whether the system is periodic along the axis.
5770 * If no unit cell is defined, nil is returned.
5773 s_Molecule_Box(VALUE self)
5777 Data_Get_Struct(self, Molecule, mol);
5778 if (mol == NULL || mol->cell == NULL)
5780 v[0] = ValueFromVector(&(mol->cell->axes[0]));
5781 v[1] = ValueFromVector(&(mol->cell->axes[1]));
5782 v[2] = ValueFromVector(&(mol->cell->axes[2]));
5783 v[3] = ValueFromVector(&(mol->cell->origin));
5784 v[4] = rb_ary_new3(3, INT2NUM(mol->cell->flags[0]), INT2NUM(mol->cell->flags[1]), INT2NUM(mol->cell->flags[2]));
5785 val = rb_ary_new4(5, v);
5791 * set_box(avec, bvec, cvec, origin = [0, 0, 0], flags = [1, 1, 1], convert_coordinates = nil)
5792 * set_box(d, origin = [0, 0, 0])
5795 * Set the unit cell parameters. Avec, bvec, and cvec can be either a Vector3D or a number.
5796 If it is a number, the x/y/z axis vector is multiplied with the given number and used
5798 Flags, if present, is a 3-member array of Integers defining whether the system is
5799 periodic along the axis.
5800 If convert_coordinates is true, then the coordinates are converted so that the fractional coordinates remain the same.
5801 In the second form, an isotropic box with cell-length d is set.
5802 In the third form, the existing box is cleared.
5803 Note: the sigma of the cell parameters is not cleared unless the periodic box itself is cleared.
5806 s_Molecule_SetBox(VALUE self, VALUE aval)
5810 static Vector ax[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
5812 Vector origin = {0, 0, 0};
5815 int i, convertCoordinates = 0;
5816 Data_Get_Struct(self, Molecule, mol);
5818 MolActionCreateAndPerform(mol, gMolActionClearBox);
5821 aval = rb_ary_to_ary(aval);
5822 for (i = 0; i < 6; i++) {
5823 if (i < RARRAY_LEN(aval))
5824 v[i] = (RARRAY_PTR(aval))[i];
5828 MolActionCreateAndPerform(mol, gMolActionClearBox);
5831 if ((v[1] == Qnil || v[2] == Qnil) && rb_obj_is_kind_of(v[0], rb_cNumeric)) {
5832 d = NUM2DBL(rb_Float(v[0]));
5833 for (i = 0; i < 3; i++)
5834 VecScale(vv[i], ax[i], d);
5836 VectorFromValue(v[1], &origin);
5837 flags[0] = flags[1] = flags[2] = 1;
5839 for (i = 0; i < 3; i++) {
5842 } else if (rb_obj_is_kind_of(v[i], rb_cNumeric)) {
5843 d = NUM2DBL(rb_Float(v[i]));
5844 VecScale(vv[i], ax[i], d);
5846 VectorFromValue(v[i], &vv[i]);
5848 flags[i] = (VecLength2(vv[i]) > 0.0);
5851 VectorFromValue(v[3], &origin);
5853 for (i = 0; i < 3; i++) {
5854 VALUE val = Ruby_ObjectAtIndex(v[4], i);
5855 flags[i] = (NUM2INT(rb_Integer(val)) != 0);
5859 convertCoordinates = 1;
5861 MolActionCreateAndPerform(mol, gMolActionSetBox, &(vv[0]), &(vv[1]), &(vv[2]), &origin, (flags[0] * 4 + flags[1] * 2 + flags[2]), convertCoordinates);
5867 * cell_periodicity -> [n1, n2, n3]
5869 * Get flags denoting whether the cell is periodic along the a/b/c axes. If the cell is not defined
5873 s_Molecule_CellPeriodicity(VALUE self)
5876 Data_Get_Struct(self, Molecule, mol);
5877 if (mol->cell == NULL)
5879 return rb_ary_new3(3, INT2FIX((int)mol->cell->flags[0]), INT2FIX((int)mol->cell->flags[1]), INT2FIX((int)mol->cell->flags[2]));
5884 * self.cell_periodicity = [n1, n2, n3] or Integer or nil
5885 * set_cell_periodicity = [n1, n2, n3] or Integer or nil
5887 * Set whether the cell is periodic along the a/b/c axes. If an integer is given as an argument,
5888 * its bits 2/1/0 (from the lowest) correspond to the a/b/c axes. Nil is equivalent to [0, 0, 0].
5889 * If cell is not defined, exception is raised.
5890 * This operation is undoable.
5893 s_Molecule_SetCellPeriodicity(VALUE self, VALUE arg)
5897 Data_Get_Struct(self, Molecule, mol);
5898 if (mol->cell == NULL)
5899 rb_raise(rb_eMolbyError, "periodic cell is not defined");
5902 else if (rb_obj_is_kind_of(arg, rb_cNumeric))
5903 flag = NUM2INT(rb_Integer(arg));
5907 arg = rb_ary_to_ary(arg);
5908 for (i = 0; i < 3 && i < RARRAY_LEN(arg); i++) {
5909 arg0 = RARRAY_PTR(arg)[i];
5910 if (arg0 != Qnil && arg0 != Qfalse && arg0 != INT2FIX(0))
5911 flag |= (1 << (2 - i));
5914 MolActionCreateAndPerform(mol, gMolActionSetCellPeriodicity, flag);
5920 * cell_flexibility -> bool
5922 * Returns the unit cell is flexible or not
5925 s_Molecule_CellFlexibility(VALUE self)
5927 rb_warn("cell_flexibility is obsolete (unit cell is always frame dependent)");
5930 Data_Get_Struct(self, Molecule, mol);
5931 if (mol->cell == NULL)
5933 if (mol->useFlexibleCell)
5935 else return Qfalse; */
5940 * self.cell_flexibility = bool
5941 * set_cell_flexibility(bool)
5943 * Change the unit cell is flexible or not
5946 s_Molecule_SetCellFlexibility(VALUE self, VALUE arg)
5948 rb_warn("set_cell_flexibility is obsolete (unit cell is always frame dependent)");
5951 Data_Get_Struct(self, Molecule, mol);
5952 MolActionCreateAndPerform(mol, gMolActionSetCellFlexibility, RTEST(arg) != 0);
5958 * cell_transform -> Transform
5960 * Get the transform matrix that converts internal coordinates to cartesian coordinates.
5961 * If cell is not defined, nil is returned.
5964 s_Molecule_CellTransform(VALUE self)
5967 Data_Get_Struct(self, Molecule, mol);
5968 if (mol == NULL || mol->cell == NULL)
5970 return ValueFromTransform(&(mol->cell->tr));
5975 * symmetry -> Array of Transforms
5976 * symmetries -> Array of Transforms
5978 * Get the currently defined symmetry operations. If no symmetry operation is defined,
5979 * returns an empty array.
5982 s_Molecule_Symmetry(VALUE self)
5987 Data_Get_Struct(self, Molecule, mol);
5988 if (mol->nsyms <= 0)
5989 return rb_ary_new();
5990 val = rb_ary_new2(mol->nsyms);
5991 for (i = 0; i < mol->nsyms; i++) {
5992 rb_ary_push(val, ValueFromTransform(&mol->syms[i]));
5999 * nsymmetries -> Integer
6001 * Get the number of currently defined symmetry operations.
6004 s_Molecule_Nsymmetries(VALUE self)
6007 Data_Get_Struct(self, Molecule, mol);
6008 return INT2NUM(mol->nsyms);
6013 * add_symmetry(Transform) -> Integer
6015 * Add a new symmetry operation. If no symmetry operation is defined and the
6016 * given argument is not an identity transform, then also add an identity
6017 * transform at the index 0.
6018 * Returns the total number of symmetries after operation.
6021 s_Molecule_AddSymmetry(VALUE self, VALUE trans)
6025 Data_Get_Struct(self, Molecule, mol);
6026 TransformFromValue(trans, &tr);
6027 MolActionCreateAndPerform(mol, gMolActionAddSymmetryOperation, &tr);
6028 return INT2NUM(mol->nsyms);
6033 * remove_symmetry(count = nil) -> Integer
6034 * remove_symmetries(count = nil) -> Integer
6036 * Remove the specified number of symmetry operations. The last added ones are removed
6037 * first. If count is nil, then all symmetry operations are removed. Returns the
6038 * number of leftover symmetries.
6041 s_Molecule_RemoveSymmetry(int argc, VALUE *argv, VALUE self)
6046 Data_Get_Struct(self, Molecule, mol);
6047 rb_scan_args(argc, argv, "01", &cval);
6051 n = NUM2INT(rb_Integer(cval));
6052 if (n < 0 || n > mol->nsyms)
6053 rb_raise(rb_eMolbyError, "the given count of symops is out of range");
6054 if (n == mol->nsyms)
6057 for (i = 0; i < n; i++)
6058 MolActionCreateAndPerform(mol, gMolActionDeleteSymmetryOperation);
6059 return INT2NUM(mol->nsyms);
6063 s_Molecule_AtomGroup_i(VALUE arg, VALUE values)
6065 Molecule *mol = (Molecule *)(((VALUE *)values)[0]);
6066 IntGroup *ig1 = (IntGroup *)(((VALUE *)values)[1]);
6067 int idx = s_Molecule_AtomIndexFromValue(mol, arg);
6068 IntGroup_RaiseIfError(IntGroupAdd(ig1, idx, 1));
6075 * atom_group {|aref| ...}
6076 * atom_group(arg1, arg2, ...)
6077 * atom_group(arg1, arg2, ...) {|aref| ...}
6079 * Specify a group of atoms. If no arguments are given, IntGroup\[0...natoms] is the result.
6080 * If arguments are given, then the atoms reprensented by the arguments are added to the
6081 * group. For a conversion of a string to an atom index, see the description
6082 * of Molecule#atom_index.
6083 * If a block is given, it is evaluated with an AtomRef (not atom index integers)
6084 * representing each atom, and the atoms are removed from the result if the block returns false.
6088 s_Molecule_AtomGroup(int argc, VALUE *argv, VALUE self)
6090 IntGroup *ig1, *ig2;
6092 Int i, startPt, interval;
6093 VALUE retval = IntGroup_Alloc(rb_cIntGroup);
6094 Data_Get_Struct(retval, IntGroup, ig1);
6095 Data_Get_Struct(self, Molecule, mol);
6097 IntGroup_RaiseIfError(IntGroupAdd(ig1, 0, mol->natoms));
6100 if (FIXNUM_P(*argv) || TYPE(*argv) == T_STRING) {
6101 i = s_Molecule_AtomIndexFromValue(mol, *argv);
6102 IntGroup_RaiseIfError(IntGroupAdd(ig1, i, 1));
6103 } else if (rb_obj_is_kind_of(*argv, rb_cIntGroup)) {
6104 ig2 = IntGroupFromValue(*argv);
6105 for (i = 0; (startPt = IntGroupGetStartPoint(ig2, i)) >= 0; i++) {
6106 interval = IntGroupGetInterval(ig2, i);
6107 IntGroup_RaiseIfError(IntGroupAdd(ig1, startPt, interval));
6109 IntGroupRelease(ig2);
6110 } else if (rb_respond_to(*argv, rb_intern("each"))) {
6112 values[0] = (VALUE)mol;
6113 values[1] = (VALUE)ig1;
6114 rb_iterate(rb_each, *argv, s_Molecule_AtomGroup_i, (VALUE)values);
6116 IntGroup_RaiseIfError(IntGroupAdd(ig1, NUM2INT(*argv), 1));
6121 if (rb_block_given_p()) {
6122 /* Evaluate the given block with an AtomRef as the argument, and delete
6123 the index if the block returns false */
6124 AtomRef *aref = AtomRefNew(mol, 0);
6125 VALUE arval = Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
6126 ig2 = IntGroupNew();
6127 IntGroupCopy(ig2, ig1);
6128 for (i = 0; (startPt = IntGroupGetNthPoint(ig2, i)) >= 0; i++) {
6130 if (startPt >= mol->natoms)
6132 aref->idx = startPt;
6133 resval = rb_yield(arval);
6135 IntGroupRemove(ig1, startPt, 1);
6137 IntGroupRelease(ig2);
6140 /* Remove points that are out of bounds */
6141 IntGroup_RaiseIfError(IntGroupRemove(ig1, mol->natoms, INT_MAX));
6148 * atom_index(val) -> Integer
6150 * Returns the atom index represented by val. val can be either a non-negative integer
6151 * (directly representing the atom index), a negative integer (representing <code>natoms - val</code>),
6152 * a string of type "resname.resid:name" or "resname:name" or "resid:name" or "name",
6153 * where resname, resid, name are the residue name, residue id, and atom name respectively.
6154 * If val is a string and multiple atoms match the description, the atom with the lowest index
6158 s_Molecule_AtomIndex(VALUE self, VALUE val)
6161 Data_Get_Struct(self, Molecule, mol);
6162 return INT2NUM(s_Molecule_AtomIndexFromValue(mol, val));
6167 * extract(group, dummy_flag = nil) -> Molecule
6169 * Extract the atoms given by group and return as a new molecule object.
6170 * If dummy_flag is true, then the atoms that are not included in the group but are connected
6171 * to any atoms in the group are converted to "dummy" atoms (i.e. with element "Du" and
6172 * names beginning with an underscore) and included in the new molecule object.
6175 s_Molecule_Extract(int argc, VALUE *argv, VALUE self)
6177 Molecule *mol1, *mol2;
6179 VALUE group, dummy_flag, retval;
6180 Data_Get_Struct(self, Molecule, mol1);
6181 rb_scan_args(argc, argv, "11", &group, &dummy_flag);
6182 ig = s_Molecule_AtomGroupFromValue(self, group);
6183 if (MoleculeExtract(mol1, &mol2, ig, (dummy_flag != Qnil && dummy_flag != Qfalse)) != 0) {
6186 retval = ValueFromMolecule(mol2);
6188 IntGroupRelease(ig);
6194 * add(molecule2) -> self
6196 * Combine two molecules. The residue numbers of the newly added atoms may be renumbered to avoid
6198 This operation is undoable.
6201 s_Molecule_Add(VALUE self, VALUE val)
6203 Molecule *mol1, *mol2;
6204 Data_Get_Struct(self, Molecule, mol1);
6205 mol2 = MoleculeFromValue(val);
6206 MolActionCreateAndPerform(mol1, gMolActionMergeMolecule, mol2, NULL);
6212 * remove(group) -> Molecule
6214 * The atoms designated by the given group are removed from the molecule.
6215 * This operation is undoable.
6218 s_Molecule_Remove(VALUE self, VALUE group)
6223 IntGroupIterator iter;
6225 Data_Get_Struct(self, Molecule, mol1);
6226 group = rb_funcall(self, rb_intern("atom_group"), 1, group);
6227 if (!rb_obj_is_kind_of(group, rb_cIntGroup))
6228 rb_raise(rb_eMolbyError, "IntGroup instance is expected");
6229 Data_Get_Struct(group, IntGroup, ig);
6231 /* Remove the bonds between the two fragments */
6232 /* (This is necessary for undo to work correctly) */
6233 IntGroupIteratorInit(ig, &iter);
6235 while ((i = IntGroupIteratorNext(&iter)) >= 0) {
6236 Atom *ap = ATOM_AT_INDEX(mol1->atoms, i);
6238 cp = AtomConnectData(&ap->connect);
6239 for (j = 0; j < ap->connect.count; j++) {
6241 if (!IntGroupLookup(ig, n, NULL)) {
6242 /* bond i-n, i is in ig and n is not */
6243 int k = MoleculeLookupBond(mol1, i, n);
6247 IntGroupAdd(bg, k, 1);
6252 IntGroupIteratorRelease(&iter);
6255 MolActionCreateAndPerform(mol1, gMolActionDeleteBonds, bg);
6256 IntGroupRelease(bg);
6259 if (MolActionCreateAndPerform(mol1, gMolActionUnmergeMolecule, ig) == 0)
6266 * create_atom(name, pos = -1) -> AtomRef
6268 * Create a new atom with the specified name (may contain residue
6269 * information) and position (if position is out of range, the atom is appended at
6270 * the end). Returns the reference to the new atom.
6271 * This operation is undoable.
6274 s_Molecule_CreateAnAtom(int argc, VALUE *argv, VALUE self)
6281 char *p, resName[6], atomName[6];
6283 Data_Get_Struct(self, Molecule, mol);
6284 rb_scan_args(argc, argv, "02", &name, &ival);
6286 pos = NUM2INT(rb_Integer(ival));
6289 p = StringValuePtr(name);
6291 i = MoleculeAnalyzeAtomName(p, resName, &resSeq, atomName);
6292 if (atomName[0] == 0)
6293 rb_raise(rb_eMolbyError, "bad atom name specification: %s", p);
6296 if (p == NULL || p[0] == 0) {
6297 memset(atomName, 0, 4);
6300 memset(&arec, 0, sizeof(arec));
6301 strncpy(arec.aname, atomName, 4);
6303 strncpy(arec.resName, resName, 4);
6304 arec.resSeq = resSeq;
6306 arec.occupancy = 1.0;
6307 // i = MoleculeCreateAnAtom(mol, &arec);
6308 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &arec, pos, &pos) != 0)
6310 aref = AtomRefNew(mol, pos);
6311 return Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
6316 * duplicate_atom(atomref, pos = -1) -> AtomRef
6318 * Create a new atom with the same attributes (but no bonding information)
6319 * with the specified atom. Returns the reference to the new atom.
6320 * This operation is undoable.
6323 s_Molecule_DuplicateAnAtom(int argc, VALUE *argv, VALUE self)
6329 VALUE retval, aval, ival;
6331 Data_Get_Struct(self, Molecule, mol);
6332 rb_scan_args(argc, argv, "11", &aval, &ival);
6333 if (FIXNUM_P(aval)) {
6334 int idx = NUM2INT(aval);
6335 if (idx < 0 || idx >= mol->natoms)
6336 rb_raise(rb_eMolbyError, "atom index out of range: %d", idx);
6337 apsrc = ATOM_AT_INDEX(mol->atoms, idx);
6339 apsrc = s_AtomFromValue(aval);
6342 rb_raise(rb_eMolbyError, "bad atom specification");
6344 pos = NUM2INT(rb_Integer(ival));
6346 AtomDuplicate(&arec, apsrc);
6347 arec.connect.count = 0;
6348 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &arec, pos, &pos) != 0)
6351 aref = AtomRefNew(mol, pos);
6352 retval = Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
6360 * create_bond(n1, n2, ...) -> Integer
6362 * Create bonds between atoms n1 and n2, n3 and n4, and so on. If the corresponding bond is already present for a particular pair,
6363 * do nothing for that pair. Returns the number of bonds actually created.
6364 * This operation is undoable.
6367 s_Molecule_CreateBond(int argc, VALUE *argv, VALUE self)
6370 Int i, j, *ip, old_nbonds;
6372 rb_raise(rb_eMolbyError, "missing arguments");
6374 rb_raise(rb_eMolbyError, "bonds should be specified by pairs of atom indices");
6375 Data_Get_Struct(self, Molecule, mol);
6376 ip = ALLOC_N(Int, argc + 1);
6377 for (i = j = 0; i < argc; i++, j++) {
6378 ip[j] = s_Molecule_AtomIndexFromValue(mol, argv[i]);
6380 if (MoleculeLookupBond(mol, ip[j - 1], ip[j]) >= 0)
6381 j -= 2; /* This bond is already present: skip it */
6384 old_nbonds = mol->nbonds;
6386 ip[j] = kInvalidIndex;
6387 i = MolActionCreateAndPerform(mol, gMolActionAddBonds, j, ip, NULL);
6391 rb_raise(rb_eMolbyError, "atom index out of range");
6393 rb_raise(rb_eMolbyError, "too many bonds");
6395 rb_raise(rb_eMolbyError, "duplicate bonds");
6397 rb_raise(rb_eMolbyError, "cannot create bond to itself");
6399 rb_raise(rb_eMolbyError, "error in creating bonds");
6400 return INT2NUM(mol->nbonds - old_nbonds);
6405 * molecule.remove_bonds(n1, n2, ...) -> Integer
6407 * Remove bonds between atoms n1 and n2, n3 and n4, and so on. If the corresponding bond is not present for
6408 * a particular pair, do nothing for that pair. Returns the number of bonds actually removed.
6409 * This operation is undoable.
6412 s_Molecule_RemoveBond(int argc, VALUE *argv, VALUE self)
6418 rb_raise(rb_eMolbyError, "missing arguments");
6420 rb_raise(rb_eMolbyError, "bonds should be specified by pairs of atom indices");
6421 Data_Get_Struct(self, Molecule, mol);
6423 for (i = j = 0; i < argc; i++, j = 1 - j) {
6424 n[j] = s_Molecule_AtomIndexFromValue(mol, argv[i]);
6426 Int k = MoleculeLookupBond(mol, n[0], n[1]);
6430 IntGroupAdd(bg, k, 1);
6435 MolActionCreateAndPerform(mol, gMolActionDeleteBonds, bg);
6436 i = IntGroupGetCount(bg);
6437 IntGroupRelease(bg);
6444 * add_angle(n1, n2, n3) -> Molecule
6446 * Add angle n1-n2-n3. Returns self. Usually, angles are automatically added
6447 * when a bond is created, so it is rarely necessary to use this method explicitly.
6448 * This operation is undoable.
6451 s_Molecule_AddAngle(VALUE self, VALUE v1, VALUE v2, VALUE v3)
6455 Data_Get_Struct(self, Molecule, mol);
6456 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6457 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6458 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6459 if (MoleculeLookupAngle(mol, n[0], n[1], n[2]) >= 0)
6460 rb_raise(rb_eMolbyError, "angle %d-%d-%d is already present", n[0], n[1], n[2]);
6461 n[3] = kInvalidIndex;
6462 MolActionCreateAndPerform(mol, gMolActionAddAngles, 3, n, NULL);
6468 * remove_angle(n1, n2, n3) -> Molecule
6470 * Remove angle n1-n2-n3. Returns self. Usually, angles are automatically removed
6471 * when a bond is removed, so it is rarely necessary to use this method explicitly.
6472 * This operation is undoable.
6475 s_Molecule_RemoveAngle(VALUE self, VALUE v1, VALUE v2, VALUE v3)
6480 Data_Get_Struct(self, Molecule, mol);
6481 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6482 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6483 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6484 if ((n[3] = MoleculeLookupAngle(mol, n[0], n[1], n[2])) < 0)
6485 rb_raise(rb_eMolbyError, "angle %d-%d-%d is not present", n[0], n[1], n[2]);
6486 ig = IntGroupNewWithPoints(n[3], 1, -1);
6487 MolActionCreateAndPerform(mol, gMolActionDeleteAngles, ig);
6488 IntGroupRelease(ig);
6494 * add_dihedral(n1, n2, n3, n4) -> Molecule
6496 * Add dihedral n1-n2-n3-n4. Returns self. Usually, dihedrals are automatically added
6497 * when a bond is created, so it is rarely necessary to use this method explicitly.
6498 * This operation is undoable.
6501 s_Molecule_AddDihedral(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6505 Data_Get_Struct(self, Molecule, mol);
6506 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6507 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6508 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6509 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6510 if (MoleculeLookupDihedral(mol, n[0], n[1], n[2], n[3]) >= 0)
6511 rb_raise(rb_eMolbyError, "dihedral %d-%d-%d-%d is already present", n[0], n[1], n[2], n[3]);
6512 n[4] = kInvalidIndex;
6513 MolActionCreateAndPerform(mol, gMolActionAddDihedrals, 4, n, NULL);
6519 * remove_dihedral(n1, n2, n3, n4) -> Molecule
6521 * Remove dihedral n1-n2-n3-n4. Returns self. Usually, dihedrals are automatically removed
6522 * when a bond is removed, so it is rarely necessary to use this method explicitly.
6523 * This operation is undoable.
6526 s_Molecule_RemoveDihedral(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6531 Data_Get_Struct(self, Molecule, mol);
6532 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6533 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6534 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6535 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6536 if ((n[4] = MoleculeLookupDihedral(mol, n[0], n[1], n[2], n[3])) < 0)
6537 rb_raise(rb_eMolbyError, "dihedral %d-%d-%d-%d is not present", n[0], n[1], n[2], n[3]);
6538 ig = IntGroupNewWithPoints(n[4], 1, -1);
6539 MolActionCreateAndPerform(mol, gMolActionDeleteDihedrals, ig);
6540 IntGroupRelease(ig);
6546 * add_improper(n1, n2, n3, n4) -> Molecule
6548 * Add dihedral n1-n2-n3-n4. Returns self. Unlike angles and dihedrals, impropers are
6549 * not automatically added when a new bond is created, so this method is more useful than
6550 * the angle/dihedral counterpart.
6551 * This operation is undoable.
6554 s_Molecule_AddImproper(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6558 Data_Get_Struct(self, Molecule, mol);
6559 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6560 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6561 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6562 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6563 if (MoleculeLookupImproper(mol, n[0], n[1], n[2], n[3]) >= 0)
6564 rb_raise(rb_eMolbyError, "improper %d-%d-%d-%d is already present", n[0], n[1], n[2], n[3]);
6565 n[4] = kInvalidIndex;
6566 MolActionCreateAndPerform(mol, gMolActionAddImpropers, 4, n, NULL);
6572 * remove_improper(n1, n2, n3, n4) -> Molecule
6574 * Remove improper n1-n2-n3-n4. Returns self. Unlike angles and dihedrals, impropers are
6575 * not automatically added when a new bond is created, so this method is more useful than
6576 * the angle/dihedral counterpart.
6577 * This operation is undoable.
6580 s_Molecule_RemoveImproper(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6585 Data_Get_Struct(self, Molecule, mol);
6586 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6587 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6588 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6589 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6590 if ((n[4] = MoleculeLookupImproper(mol, n[0], n[1], n[2], n[3])) < 0)
6591 rb_raise(rb_eMolbyError, "improper %d-%d-%d-%d is not present", n[0], n[1], n[2], n[3]);
6592 ig = IntGroupNewWithPoints(n[4], 1, -1);
6593 MolActionCreateAndPerform(mol, gMolActionDeleteImpropers, ig);
6594 IntGroupRelease(ig);
6600 * assign_residue(group, res) -> Molecule
6602 * Assign the specified atoms as the given residue. res can either be an integer, "resname"
6603 * or "resname.resno". When the residue number is not specified, the residue number of
6604 * the first atom in the group is used.
6605 * This operation is undoable.
6608 s_Molecule_AssignResidue(VALUE self, VALUE range, VALUE res)
6612 char *p, *pp, buf[16];
6615 Data_Get_Struct(self, Molecule, mol);
6617 /* Parse the argument res */
6618 if (FIXNUM_P(res)) {
6619 /* We can assume Fixnum here because Bignum is non-realistic as residue numbers */
6620 resid = NUM2INT(res);
6623 p = StringValuePtr(res);
6624 pp = strchr(p, '.');
6626 resid = atoi(pp + 1);
6632 if (n > sizeof buf - 1)
6637 ig = s_Molecule_AtomGroupFromValue(self, range);
6638 if (ig == NULL || IntGroupGetCount(ig) == 0)
6642 /* Use the residue number of the first specified atom */
6643 n = IntGroupGetNthPoint(ig, 0);
6644 if (n >= mol->natoms)
6645 rb_raise(rb_eMolbyError, "Atom index (%d) out of range", n);
6646 ap = ATOM_AT_INDEX(mol->atoms, n);
6649 /* Change the residue number */
6650 MolActionCreateAndPerform(mol, gMolActionChangeResidueNumber, ig, resid);
6651 /* Change the residue name if necessary */
6655 seqs[1] = kInvalidIndex; */
6656 MolActionCreateAndPerform(mol, gMolActionChangeResidueNames, 1, &resid, 4, buf);
6658 IntGroupRelease(ig);
6664 * offset_residue(group, offset) -> Molecule
6666 * Offset the residue number of the specified atoms. If any of the residue number gets
6667 * negative, then exception is thrown.
6668 * This operation is undoable.
6671 s_Molecule_OffsetResidue(VALUE self, VALUE range, VALUE offset)
6676 Data_Get_Struct(self, Molecule, mol);
6677 ig = s_Molecule_AtomGroupFromValue(self, range);
6678 ofs = NUM2INT(offset);
6679 result = MolActionCreateAndPerform(mol, gMolActionOffsetResidueNumbers, ig, ofs, -1);
6681 rb_raise(rb_eMolbyError, "residue number of atom %d becomes negative", result - 1);
6682 IntGroupRelease(ig);
6688 * renumber_atoms(array) -> IntGroup
6690 * Change the order of atoms so that the atoms specified in the array argument appear
6691 * in this order from the top of the molecule. The atoms that are not included in array
6692 * are placed after these atoms, and these atoms are returned as an intGroup.
6693 * This operation is undoable.
6696 s_Molecule_RenumberAtoms(VALUE self, VALUE array)
6702 VALUE *valp, retval;
6703 Data_Get_Struct(self, Molecule, mol);
6704 if (TYPE(array) != T_ARRAY)
6705 array = rb_funcall(array, rb_intern("to_a"), 0);
6706 n = RARRAY_LEN(array);
6707 valp = RARRAY_PTR(array);
6708 new2old = ALLOC_N(Int, n + 1);
6709 for (i = 0; i < n; i++)
6710 new2old[i] = s_Molecule_AtomIndexFromValue(mol, valp[i]);
6711 new2old[i] = kInvalidIndex;
6712 i = MolActionCreateAndPerform(mol, gMolActionRenumberAtoms, i, new2old);
6714 rb_raise(rb_eMolbyError, "Atom index out of range");
6716 rb_raise(rb_eMolbyError, "Duplicate entry");
6718 rb_raise(rb_eMolbyError, "Internal inconsistency during atom renumbering");
6719 retval = IntGroup_Alloc(rb_cIntGroup);
6720 Data_Get_Struct(retval, IntGroup, ig);
6721 if (mol->natoms > n)
6722 IntGroup_RaiseIfError(IntGroupAdd(ig, n, mol->natoms - n));
6729 * find_close_atoms(atom, limit = 1.2) -> array of Integers (atom indices)
6731 * Find atoms that are within the threshold distance from the given atom.
6732 * If limit is a positive number, the threshold distance is the sum of the vdw radii times limit.
6733 * If limit is a negative number, its absolute value is used for the threshold distance in angstrom.
6734 * If limit is not given, a default value of 1.2 is used.
6735 * An array of atom indices is returned. If no atoms are found, an empty array is returned.
6738 s_Molecule_FindCloseAtoms(int argc, VALUE *argv, VALUE self)
6743 Int n1, nbonds, *bonds;
6744 Data_Get_Struct(self, Molecule, mol);
6745 rb_scan_args(argc, argv, "11", &aval, &limval);
6746 n1 = s_Molecule_AtomIndexFromValue(mol, aval);
6750 limit = NUM2DBL(rb_Float(limval));
6751 nbonds = 0; /* This initialization is necessary: see comments in MoleculeFindCloseAtoms() */
6753 MoleculeFindCloseAtoms(mol, n1, limit, &nbonds, &bonds, 0);
6754 aval = rb_ary_new();
6756 for (n1 = 0; n1 < nbonds; n1++)
6757 rb_ary_push(aval, INT2NUM(bonds[n1 * 2 + 1]));
6765 * guess_bonds(limit = 1.2) -> Integer
6767 * Create bonds between atoms that are within the threshold distance.
6768 * If limit is a positive number, the threshold distance is the sum of the vdw radii times limit.
6769 * If limit is a negative number, its absolute value is used for the threshold distance in angstrom.
6770 * If limit is not given, a default value of 1.2 is used.
6771 * The number of the newly created bonds is returned.
6772 * This operation is undoable.
6775 s_Molecule_GuessBonds(int argc, VALUE *argv, VALUE self)
6781 Data_Get_Struct(self, Molecule, mol);
6782 rb_scan_args(argc, argv, "01", &limval);
6786 limit = NUM2DBL(rb_Float(limval));
6787 MoleculeGuessBonds(mol, limit, &nbonds, &bonds);
6789 MolActionCreateAndPerform(mol, gMolActionAddBonds, nbonds * 2, bonds, NULL);
6792 return INT2NUM(nbonds);
6797 * register_undo(script, *args)
6799 * Register an undo operation with the current molecule.
6802 s_Molecule_RegisterUndo(int argc, VALUE *argv, VALUE self)
6807 Data_Get_Struct(self, Molecule, mol);
6808 rb_scan_args(argc, argv, "1*", &script, &args);
6809 act = MolActionNew(SCRIPT_ACTION("R"), StringValuePtr(script), args);
6810 MolActionCallback_registerUndo(mol, act);
6816 * undo_enabled? -> bool
6818 * Returns true if undo is enabled for this molecule; otherwise no.
6821 s_Molecule_UndoEnabled(VALUE self)
6824 Data_Get_Struct(self, Molecule, mol);
6825 if (MolActionCallback_isUndoRegistrationEnabled(mol))
6832 * undo_enabled = bool
6834 * Enable or disable undo.
6837 s_Molecule_SetUndoEnabled(VALUE self, VALUE val)
6840 Data_Get_Struct(self, Molecule, mol);
6841 MolActionCallback_setUndoRegistrationEnabled(mol, (val != Qfalse && val != Qnil));
6847 * selection -> IntGroup
6849 * Returns the current selection.
6852 s_Molecule_Selection(VALUE self)
6857 Data_Get_Struct(self, Molecule, mol);
6858 if (mol != NULL && (ig = MoleculeGetSelection(mol)) != NULL) {
6859 ig = IntGroupNewFromIntGroup(ig); /* Duplicate, so that the change from GUI does not affect the value */
6860 val = ValueFromIntGroup(ig);
6861 IntGroupRelease(ig);
6863 val = IntGroup_Alloc(rb_cIntGroup);
6869 s_Molecule_SetSelectionSub(VALUE self, VALUE val, int undoable)
6873 Data_Get_Struct(self, Molecule, mol);
6877 ig = s_Molecule_AtomGroupFromValue(self, val);
6879 MolActionCreateAndPerform(mol, gMolActionSetSelection, ig);
6881 MoleculeSetSelection(mol, ig);
6883 IntGroupRelease(ig);
6889 * selection = IntGroup
6891 * Set the current selection. The right-hand operand may be nil.
6892 * This operation is _not_ undoable. If you need undo, use set_undoable_selection instead.
6895 s_Molecule_SetSelection(VALUE self, VALUE val)
6897 return s_Molecule_SetSelectionSub(self, val, 0);
6902 * set_undoable_selection(IntGroup)
6904 * Set the current selection with undo registration. The right-hand operand may be nil.
6905 * This operation is undoable.
6908 s_Molecule_SetUndoableSelection(VALUE self, VALUE val)
6910 return s_Molecule_SetSelectionSub(self, val, 1);
6915 * hidden_atoms -> IntGroup
6917 * Returns the currently hidden atoms.
6920 s_Molecule_HiddenAtoms(VALUE self)
6922 rb_raise(rb_eMolbyError, "set_hidden_atoms is now obsolete. Try using Molecule#is_atom_visible or AtomRef#hidden.");
6923 return Qnil; /* Not reached */
6927 Data_Get_Struct(self, Molecule, mol);
6932 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
6933 if (ap->exflags & kAtomHiddenFlag)
6934 IntGroupAdd(ig, i, 1);
6936 val = ValueFromIntGroup(ig);
6937 IntGroupRelease(ig);
6940 } else return Qnil; */
6945 * set_hidden_atoms(IntGroup)
6946 * self.hidden_atoms = IntGroup
6948 * Hide the specified atoms. This operation is _not_ undoable.
6951 s_Molecule_SetHiddenAtoms(VALUE self, VALUE val)
6953 rb_raise(rb_eMolbyError, "set_hidden_atoms is now obsolete. Try using Molecule#is_atom_visible or AtomRef#hidden.");
6954 return Qnil; /* Not reached */
6957 Data_Get_Struct(self, Molecule, mol);
6965 ig = s_Molecule_AtomGroupFromValue(self, val);
6966 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
6967 if (ig != NULL && IntGroupLookup(ig, i, NULL)) {
6968 ap->exflags |= kAtomHiddenFlag;
6970 ap->exflags &= kAtomHiddenFlag;
6974 IntGroupRelease(ig);
6975 MoleculeCallback_notifyModification(mol, 0);
6982 * select_frame(index)
6985 * Select the specified frame. If successful, returns true, otherwise returns false.
6988 s_Molecule_SelectFrame(VALUE self, VALUE val)
6991 int ival = NUM2INT(val);
6992 Data_Get_Struct(self, Molecule, mol);
6993 ival = MoleculeSelectFrame(mol, ival, 1);
7003 * Get the current frame.
7006 s_Molecule_Frame(VALUE self)
7009 Data_Get_Struct(self, Molecule, mol);
7010 return INT2NUM(mol->cframe);
7015 * nframes -> Integer
7017 * Get the number of frames.
7020 s_Molecule_Nframes(VALUE self)
7023 Data_Get_Struct(self, Molecule, mol);
7024 return INT2NUM(MoleculeGetNumberOfFrames(mol));
7029 * insert_frame(integer, coordinates = nil, cell_axes = nil) -> bool
7030 * insert_frames(intGroup = nil, coordinates = nil, cell_axes = nil) -> bool
7032 * Insert new frames at the indices specified by the intGroup. If the first argument is
7033 * an integer, a single new frame is inserted at that index. If the first argument is
7034 * nil, a new frame is inserted at the last. If non-nil coordinates is given, it
7035 * should be an array of arrays of Vector3Ds, then those coordinates are set
7036 * to the new frame. Otherwise, the coordinates of current molecule are copied
7038 * Returns an intGroup representing the inserted frames if successful, nil if not.
7041 s_Molecule_InsertFrames(int argc, VALUE *argv, VALUE self)
7043 VALUE val, coords, cells;
7046 int count, ival, i, j, len, len_c, len2, nframes;
7049 Data_Get_Struct(self, Molecule, mol);
7050 rb_scan_args(argc, argv, "12", &val, &coords, &cells);
7051 if (coords != Qnil) {
7052 if (TYPE(coords) != T_ARRAY)
7053 rb_raise(rb_eTypeError, "the coordinates should be given as an array of Vector3D");
7054 len = RARRAY_LEN(coords);
7056 if (cells != Qnil) {
7057 if (mol->cell == NULL)
7058 rb_raise(rb_eTypeError, "the unit cell is not defined but the cell axes are given");
7059 if (TYPE(cells) != T_ARRAY)
7060 rb_raise(rb_eTypeError, "the cell axes should be given as an array of Vector3D");
7061 len_c = RARRAY_LEN(cells);
7063 count = (len > len_c ? len : len_c); /* May be zero; will be updated later */
7064 nframes = MoleculeGetNumberOfFrames(mol);
7066 ig = IntGroupNewWithPoints(nframes, (count > 0 ? count : 1), -1);
7067 val = ValueFromIntGroup(ig);
7069 ig = IntGroupFromValue(val);
7071 count = IntGroupGetCount(ig); /* Count is updated here */
7072 vp = ALLOC_N(Vector, mol->natoms * count);
7074 vp2 = ALLOC_N(Vector, 4 * count);
7078 rb_raise(rb_eMolbyError, "the coordinates should contain no less than %d arrays (for frames)", count);
7079 ptr = RARRAY_PTR(coords);
7080 for (i = 0; i < count; i++) {
7081 if (TYPE(ptr[i]) != T_ARRAY)
7082 rb_raise(rb_eTypeError, "the coordinate array contains non-array object at index %d", i);
7083 len2 = RARRAY_LEN(ptr[i]);
7084 if (len2 < mol->natoms)
7085 rb_raise(rb_eMolbyError, "the array at index %d contains less than %d elements", i, mol->natoms);
7086 ptr2 = RARRAY_PTR(ptr[i]);
7087 for (j = 0; j < mol->natoms; j++)
7088 VectorFromValue(ptr2[j], &vp[i * mol->natoms + j]);
7092 for (i = 0; i < count; i++) {
7093 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
7094 vp[i * mol->natoms + j] = ap->r;
7100 rb_raise(rb_eMolbyError, "the cell vectors should contain no less than %d arrays (for frames)", count);
7101 ptr = RARRAY_PTR(cells);
7102 for (i = 0; i < count; i++) {
7103 if (TYPE(ptr[i]) != T_ARRAY)
7104 rb_raise(rb_eTypeError, "the cell parameter array contains non-array object at index %d", i);
7105 len2 = RARRAY_LEN(ptr[i]);
7107 rb_raise(rb_eMolbyError, "the cell parameter should contain 4 vectors");
7108 ptr2 = RARRAY_PTR(ptr[i]);
7109 for (j = 0; j < 4; j++)
7110 VectorFromValue(ptr2[j], &vp2[i * 4 + j]);
7113 ival = MolActionCreateAndPerform(mol, gMolActionInsertFrames, ig, mol->natoms * count, vp, (vp2 != NULL ? 4 * count : 0), vp2);
7114 IntGroupRelease(ig);
7118 return (ival >= 0 ? val : Qnil);
7123 * create_frame(coordinates = nil) -> Integer
7124 * create_frames(coordinates = nil) -> Integer
7126 * Same as molecule.insert_frames(nil, coordinates).
7129 s_Molecule_CreateFrames(int argc, VALUE *argv, VALUE self)
7132 rb_scan_args(argc, argv, "02", &vals[1], &vals[2]);
7134 return s_Molecule_InsertFrames(3, vals, self);
7139 * remove_frames(IntGroup, wantCoordinates = false)
7141 * Remove the frames at group. If wantsCoordinates is false (default), returns true if successful
7142 * and nil otherwise. If wantsCoordinates is true, an array of arrays of the coordinates in the
7143 * removed frames is returned if operation is successful.
7146 s_Molecule_RemoveFrames(int argc, VALUE *argv, VALUE self)
7153 Data_Get_Struct(self, Molecule, mol);
7154 rb_scan_args(argc, argv, "11", &val, &flag);
7155 ig = IntGroupFromValue(val);
7156 count = IntGroupGetCount(ig);
7158 /* Create return value before removing frames */
7163 retval = rb_ary_new2(count);
7164 for (i = 0; i < count; i++) {
7165 n = IntGroupGetNthPoint(ig, i);
7166 coords = rb_ary_new2(mol->natoms);
7167 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
7168 if (n < ap->nframes && n != mol->cframe)
7171 rb_ary_push(coords, ValueFromVector(&v));
7173 rb_ary_push(retval, coords);
7175 } else retval = Qtrue;
7176 if (MolActionCreateAndPerform(mol, gMolActionRemoveFrames, ig) >= 0)
7183 * each_frame {|n| ...}
7185 * Set the frame number from 0 to nframes-1 and execute the block. The block argument is
7186 * the frame number. After completion, the original frame number is restored.
7189 s_Molecule_EachFrame(VALUE self)
7191 int i, cframe, nframes;
7193 Data_Get_Struct(self, Molecule, mol);
7194 cframe = mol->cframe;
7195 nframes = MoleculeGetNumberOfFrames(mol);
7197 for (i = 0; i < nframes; i++) {
7198 MoleculeSelectFrame(mol, i, 1);
7199 rb_yield(INT2NUM(i));
7201 MoleculeSelectFrame(mol, cframe, 1);
7208 * set_atom_attr(index, key, value)
7210 * Set the atom attribute for the specified atom.
7211 * This operation is undoable.
7214 s_Molecule_SetAtomAttr(VALUE self, VALUE idx, VALUE key, VALUE val)
7218 Data_Get_Struct(self, Molecule, mol);
7219 aref = ValueFromMoleculeAndIndex(mol, s_Molecule_AtomIndexFromValue(mol, idx));
7220 oldval = s_AtomRef_GetAttr(aref, key);
7223 s_AtomRef_SetAttr(aref, key, val);
7229 * get_atom_attr(index, key)
7231 * Get the atom attribute for the specified atom.
7234 s_Molecule_GetAtomAttr(VALUE self, VALUE idx, VALUE key)
7236 return s_Molecule_SetAtomAttr(self, idx, key, Qundef);
7241 * get_coord_from_frame(index, group = nil)
7243 * Copy the coordinates from the indicated frame. If group is specified, only the specified atoms
7244 * are modified. Third argument (cflag) is now obsolete (it used to specify whether the cell parameters are to be
7245 * copied; now they are always copied)
7248 s_Molecule_GetCoordFromFrame(int argc, VALUE *argv, VALUE self)
7251 VALUE ival, gval, cval;
7252 Int index, i, j, n, nn;
7254 IntGroupIterator iter;
7257 Data_Get_Struct(self, Molecule, mol);
7258 rb_scan_args(argc, argv, "12", &ival, &gval, &cval);
7260 rb_warn("The 3rd argument to get_coord_from_frame() is now obsolete");
7261 index = NUM2INT(rb_Integer(ival));
7262 if (index < 0 || index >= (n = MoleculeGetNumberOfFrames(mol))) {
7264 rb_raise(rb_eMolbyError, "No frame is present");
7266 rb_raise(rb_eMolbyError, "Frame index (%d) out of range (should be 0..%d)", index, n - 1);
7269 ig = IntGroupNewWithPoints(0, mol->natoms, -1);
7271 ig = s_Molecule_AtomGroupFromValue(self, gval);
7273 n = IntGroupGetCount(ig);
7275 vp = (Vector *)calloc(sizeof(Vector), n);
7276 IntGroupIteratorInit(ig, &iter);
7279 while ((i = IntGroupIteratorNext(&iter)) >= 0) {
7280 ap = ATOM_AT_INDEX(mol->atoms, i);
7281 if (index < ap->nframes) {
7282 vp[j] = ap->frames[index];
7290 MolActionCreateAndPerform(mol, gMolActionSetAtomPositions, ig, n, vp);
7292 if (mol->cell != NULL && mol->frame_cells != NULL && index < mol->nframe_cells) {
7293 vp = mol->frame_cells + index * 4;
7294 MolActionCreateAndPerform(mol, gMolActionSetBox, vp, vp + 1, vp + 2, vp + 3, -1, 0);
7296 IntGroupIteratorRelease(&iter);
7298 IntGroupRelease(ig);
7304 * fragment(n1, *exatoms) -> IntGroup
7305 * fragment(group, *exatoms) -> IntGroup
7307 * Get the fragment including the atom n1 or the atom group. If additional arguments are given,
7308 * those atoms will not be counted during the search.
7311 s_Molecule_Fragment(int argc, VALUE *argv, VALUE self)
7314 IntGroup *baseg, *ig, *exatoms;
7316 volatile VALUE nval, exval;
7317 Data_Get_Struct(self, Molecule, mol);
7318 rb_scan_args(argc, argv, "1*", &nval, &exval);
7319 if (rb_obj_is_kind_of(nval, rb_cNumeric) || rb_obj_is_kind_of(nval, rb_cString)) {
7321 n = NUM2INT(s_Molecule_AtomIndex(self, nval));
7323 baseg = s_Molecule_AtomGroupFromValue(self, nval);
7325 if (RARRAY_LEN(exval) == 0) {
7328 exval = s_Molecule_AtomGroup(RARRAY_LEN(exval), RARRAY_PTR(exval), self);
7329 Data_Get_Struct(exval, IntGroup, exatoms);
7331 if (baseg == NULL) {
7332 ig = MoleculeFragmentExcludingAtomGroup(mol, n, exatoms);
7334 IntGroupIterator iter;
7335 IntGroupIteratorInit(baseg, &iter);
7336 if ((n = IntGroupIteratorNext(&iter)) < 0) {
7339 ig = MoleculeFragmentExcludingAtomGroup(mol, n, exatoms);
7341 while ((n = IntGroupIteratorNext(&iter)) >= 0) {
7343 subg = MoleculeFragmentExcludingAtomGroup(mol, n, exatoms);
7345 IntGroupAddIntGroup(ig, subg);
7346 IntGroupRelease(subg);
7351 IntGroupIteratorRelease(&iter);
7352 IntGroupRelease(baseg);
7355 rb_raise(rb_eMolbyError, "invalid specification of molecular fragment");
7356 nval = ValueFromIntGroup(ig);
7357 IntGroupRelease(ig);
7363 * each_fragment {|group| ...}
7365 * Execute the block, with the IntGroup object for each fragment as the argument.
7366 * Atoms or bonds should not be added or removed during the execution of the block.
7369 s_Molecule_EachFragment(VALUE self)
7374 Data_Get_Struct(self, Molecule, mol);
7375 if (mol == NULL || mol->natoms == 0)
7377 ag = IntGroupNewWithPoints(0, mol->natoms, -1);
7378 while (IntGroupGetCount(ag) > 0) {
7379 int n = IntGroupGetNthPoint(ag, 0);
7380 fg = MoleculeFragmentExcludingAtomGroup(mol, n, NULL);
7382 rb_raise(rb_eMolbyError, "internal error during each_fragment");
7383 gval = ValueFromIntGroup(fg);
7385 IntGroupRemoveIntGroup(ag, fg);
7386 IntGroupRelease(fg);
7388 IntGroupRelease(ag);
7394 * detachable?(group) -> [n1, n2]
7396 * Check whether the group is 'detachable', i.e. the group is bound to the rest
7397 * of the molecule via only one bond. If it is, then the indices of the atoms
7398 * belonging to the bond is returned, the first element being the atom included
7399 * in the fragment. Otherwise, Qnil is returned.
7402 s_Molecule_Detachable_P(VALUE self, VALUE gval)
7408 Data_Get_Struct(self, Molecule, mol);
7409 ig = s_Molecule_AtomGroupFromValue(self, gval);
7410 if (MoleculeIsFragmentDetachable(mol, ig, &n1, &n2)) {
7411 retval = rb_ary_new3(2, INT2NUM(n1), INT2NUM(n2));
7412 } else retval = Qnil;
7413 IntGroupRelease(ig);
7419 * bonds_on_border(group = selection) -> Array of Array of two Integers
7421 * Returns an array of bonds that connect an atom in the group and an atom out
7422 * of the group. The first atom in the bond always belongs to the group. If no
7423 * such bonds are present, an empty array is returned.
7426 s_Molecule_BondsOnBorder(int argc, VALUE *argv, VALUE self)
7431 Data_Get_Struct(self, Molecule, mol);
7432 rb_scan_args(argc, argv, "01", &gval);
7434 ig = MoleculeGetSelection(mol);
7438 ig = s_Molecule_AtomGroupFromValue(self, gval);
7440 retval = rb_ary_new();
7443 bg = MoleculeSearchBondsAcrossAtomGroup(mol, ig);
7445 IntGroupIterator iter;
7447 IntGroupIteratorInit(bg, &iter);
7448 while ((i = IntGroupIteratorNext(&iter)) >= 0) {
7449 /* The atoms at the border */
7451 n1 = mol->bonds[i * 2];
7452 n2 = mol->bonds[i * 2 + 1];
7453 if (IntGroupLookupPoint(ig, n1) < 0) {
7457 if (IntGroupLookupPoint(ig, n1) < 0)
7458 continue; /* Actually this is an internal error */
7460 rb_ary_push(retval, rb_ary_new3(2, INT2NUM(n1), INT2NUM(n2)));
7462 IntGroupIteratorRelease(&iter);
7464 IntGroupRelease(bg);
7465 IntGroupRelease(ig);
7471 * translate(vec, group = nil) -> Molecule
7473 * Translate the molecule by vec. If group is given, only atoms in the group are moved.
7474 * This operation is undoable.
7477 s_Molecule_Translate(int argc, VALUE *argv, VALUE self)
7483 Data_Get_Struct(self, Molecule, mol);
7484 rb_scan_args(argc, argv, "11", &vec, &group);
7485 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7486 VectorFromValue(vec, &v);
7487 // MoleculeTranslate(mol, &v, ig);
7488 MolActionCreateAndPerform(mol, gMolActionTranslateAtoms, &v, ig);
7490 IntGroupRelease(ig);
7496 * rotate(axis, angle, center = [0,0,0], group = nil) -> Molecule
7498 * Rotate the molecule. The axis must not a zero vector. angle is given in degree.
7499 * If group is given, only atoms in the group are moved.
7500 * This operation is undoable.
7503 s_Molecule_Rotate(int argc, VALUE *argv, VALUE self)
7506 volatile VALUE aval, anval, cval, gval;
7511 Data_Get_Struct(self, Molecule, mol);
7512 rb_scan_args(argc, argv, "22", &aval, &anval, &cval, &gval);
7513 ig = (NIL_P(gval) ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
7514 angle = NUM2DBL(rb_Float(anval)) * kDeg2Rad;
7515 VectorFromValue(aval, &av);
7517 cv.x = cv.y = cv.z = 0.0;
7519 VectorFromValue(cval, &cv);
7520 if (TransformForRotation(tr, &av, angle, &cv))
7521 rb_raise(rb_eMolbyError, "rotation axis cannot be a zero vector");
7522 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7524 IntGroupRelease(ig);
7530 * reflect(axis, center = [0,0,0], group = nil) -> Molecule
7532 * Reflect the molecule by the plane which is perpendicular to axis and including center.
7533 * axis must not be a zero vector.
7534 * If group is given, only atoms in the group are moved.
7535 * This operation is undoable.
7538 s_Molecule_Reflect(int argc, VALUE *argv, VALUE self)
7541 volatile VALUE aval, cval, gval;
7545 Data_Get_Struct(self, Molecule, mol);
7546 rb_scan_args(argc, argv, "12", &aval, &cval, &gval);
7547 ig = (NIL_P(gval) ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
7548 VectorFromValue(aval, &av);
7550 cv.x = cv.y = cv.z = 0.0;
7552 VectorFromValue(cval, &cv);
7553 if (TransformForReflection(tr, &av, &cv))
7554 rb_raise(rb_eMolbyError, "reflection axis cannot be a zero vector");
7555 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7557 IntGroupRelease(ig);
7563 * invert(center = [0,0,0], group = nil) -> Molecule
7565 * Invert the molecule with the given center.
7566 * If group is given, only atoms in the group are moved.
7567 * This operation is undoable.
7570 s_Molecule_Invert(int argc, VALUE *argv, VALUE self)
7573 volatile VALUE cval, gval;
7577 Data_Get_Struct(self, Molecule, mol);
7578 rb_scan_args(argc, argv, "02", &cval, &gval);
7579 ig = (NIL_P(gval) ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
7581 cv.x = cv.y = cv.z = 0.0;
7583 VectorFromValue(cval, &cv);
7584 TransformForInversion(tr, &cv);
7585 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7587 IntGroupRelease(ig);
7593 * transform(transform, group = nil) -> Molecule
7595 * Transform the molecule by the given Transform object.
7596 * If group is given, only atoms in the group are moved.
7597 * This operation is undoable.
7600 s_Molecule_Transform(int argc, VALUE *argv, VALUE self)
7606 Data_Get_Struct(self, Molecule, mol);
7607 rb_scan_args(argc, argv, "11", &trans, &group);
7608 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7609 TransformFromValue(trans, &tr);
7610 /* MoleculeTransform(mol, tr, ig); */
7611 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7613 IntGroupRelease(ig);
7618 s_Molecule_DoCenterOfMass(Molecule *mol, Vector *outv, IntGroup *ig)
7620 switch (MoleculeCenterOfMass(mol, outv, ig)) {
7621 case 2: rb_raise(rb_eMolbyError, "atom group is empty"); break;
7622 case 3: rb_raise(rb_eMolbyError, "weight is zero --- atomic weights are not defined?"); break;
7624 default: rb_raise(rb_eMolbyError, "cannot calculate center of mass"); break;
7630 * center_of_mass(group = nil) -> Vector3D
7632 * Calculate the center of mass for the given set of atoms. The argument
7633 * group is null, then all atoms are considered.
7636 s_Molecule_CenterOfMass(int argc, VALUE *argv, VALUE self)
7642 Data_Get_Struct(self, Molecule, mol);
7643 rb_scan_args(argc, argv, "01", &group);
7644 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7645 s_Molecule_DoCenterOfMass(mol, &v, ig);
7647 IntGroupRelease(ig);
7648 return ValueFromVector(&v);
7653 * centralize(group = nil) -> self
7655 * Translate the molecule so that the center of mass of the given group is located
7656 * at (0, 0, 0). Equivalent to molecule.translate(molecule.center_of_mass(group) * -1).
7659 s_Molecule_Centralize(int argc, VALUE *argv, VALUE self)
7665 Data_Get_Struct(self, Molecule, mol);
7666 rb_scan_args(argc, argv, "01", &group);
7667 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7668 s_Molecule_DoCenterOfMass(mol, &v, ig);
7670 IntGroupRelease(ig);
7674 MolActionCreateAndPerform(mol, gMolActionTranslateAtoms, &v, NULL);
7680 * bounds(group = nil) -> [min, max]
7682 * Calculate the boundary. The return value is an array of two Vector3D objects.
7685 s_Molecule_Bounds(int argc, VALUE *argv, VALUE self)
7693 Data_Get_Struct(self, Molecule, mol);
7694 rb_scan_args(argc, argv, "01", &group);
7695 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7696 if (ig != NULL && IntGroupGetCount(ig) == 0)
7697 rb_raise(rb_eMolbyError, "atom group is empty");
7698 vmin.x = vmin.y = vmin.z = 1e30;
7699 vmax.x = vmax.y = vmax.z = -1e30;
7700 for (n = 0, ap = mol->atoms; n < mol->natoms; n++, ap = ATOM_NEXT(ap)) {
7702 if (ig != NULL && IntGroupLookup(ig, n, NULL) == 0)
7718 return rb_ary_new3(2, ValueFromVector(&vmin), ValueFromVector(&vmax));
7721 /* Get atom position or a vector */
7723 s_Molecule_GetVectorFromArg(Molecule *mol, VALUE val, Vector *vp)
7725 if (rb_obj_is_kind_of(val, rb_cInteger) || rb_obj_is_kind_of(val, rb_cString)) {
7726 int n1 = s_Molecule_AtomIndexFromValue(mol, val);
7727 *vp = ATOM_AT_INDEX(mol->atoms, n1)->r;
7729 VectorFromValue(val, vp);
7735 * measure_bond(n1, n2) -> Float
7737 * Calculate the bond length. The arguments can either be atom indices, the "residue:name" representation,
7738 * or Vector3D values.
7739 * If the crystallographic cell is defined, then the internal coordinates are convereted to the cartesian.
7742 s_Molecule_MeasureBond(VALUE self, VALUE nval1, VALUE nval2)
7746 Data_Get_Struct(self, Molecule, mol);
7747 s_Molecule_GetVectorFromArg(mol, nval1, &v1);
7748 s_Molecule_GetVectorFromArg(mol, nval2, &v2);
7749 return rb_float_new(MoleculeMeasureBond(mol, &v1, &v2));
7754 * measure_angle(n1, n2, n3) -> Float
7756 * Calculate the bond angle. The arguments can either be atom indices, the "residue:name" representation,
7757 * or Vector3D values. The return value is in degree.
7758 * If the crystallographic cell is defined, then the internal coordinates are convereted to the cartesian.
7761 s_Molecule_MeasureAngle(VALUE self, VALUE nval1, VALUE nval2, VALUE nval3)
7766 Data_Get_Struct(self, Molecule, mol);
7767 s_Molecule_GetVectorFromArg(mol, nval1, &v1);
7768 s_Molecule_GetVectorFromArg(mol, nval2, &v2);
7769 s_Molecule_GetVectorFromArg(mol, nval3, &v3);
7770 d = MoleculeMeasureAngle(mol, &v1, &v2, &v3);
7772 return Qnil; /* Cannot define */
7773 else return rb_float_new(d);
7778 * measure_dihedral(n1, n2, n3, n4) -> Float
7780 * Calculate the dihedral angle. The arguments can either be atom indices, the "residue:name" representation,
7781 * or Vector3D values. The return value is in degree.
7782 * If the crystallographic cell is defined, then the internal coordinates are convereted to the cartesian.
7785 s_Molecule_MeasureDihedral(VALUE self, VALUE nval1, VALUE nval2, VALUE nval3, VALUE nval4)
7788 Vector v1, v2, v3, v4;
7790 Data_Get_Struct(self, Molecule, mol);
7791 s_Molecule_GetVectorFromArg(mol, nval1, &v1);
7792 s_Molecule_GetVectorFromArg(mol, nval2, &v2);
7793 s_Molecule_GetVectorFromArg(mol, nval3, &v3);
7794 s_Molecule_GetVectorFromArg(mol, nval4, &v4);
7795 d = MoleculeMeasureDihedral(mol, &v1, &v2, &v3, &v4);
7797 return Qnil; /* Cannot define */
7798 else return rb_float_new(d);
7803 * expand_by_symmetry(group, sym, dx=0, dy=0, dz=0) -> Array
7805 * Expand the specified part of the molecule by the given symmetry operation.
7806 * Returns the array of atom indices corresponding to the expanded atoms.
7809 s_Molecule_ExpandBySymmetry(int argc, VALUE *argv, VALUE self)
7812 VALUE gval, sval, xval, yval, zval, rval;
7818 Data_Get_Struct(self, Molecule, mol);
7819 rb_scan_args(argc, argv, "23", &gval, &sval, &xval, &yval, &zval);
7820 n[0] = NUM2INT(rb_Integer(sval));
7821 n[1] = (xval == Qnil ? 0 : NUM2INT(rb_Integer(xval)));
7822 n[2] = (yval == Qnil ? 0 : NUM2INT(rb_Integer(yval)));
7823 n[3] = (zval == Qnil ? 0 : NUM2INT(rb_Integer(zval)));
7824 ig = s_Molecule_AtomGroupFromValue(self, gval);
7825 if (n[0] < 0 || n[0] >= mol->nsyms)
7826 rb_raise(rb_eMolbyError, "symmetry index is out of bounds");
7827 natoms = mol->natoms;
7829 MolActionCreateAndPerform(mol, gMolActionExpandBySymmetry, ig, n[1], n[2], n[3], n[0], &nidx, &idx);
7831 rval = rb_ary_new2(nidx);
7832 while (--nidx >= 0) {
7833 rb_ary_store(rval, nidx, INT2NUM(idx[nidx]));
7835 /* if (natoms == mol->natoms)
7838 rval = IntGroup_Alloc(rb_cIntGroup);
7839 Data_Get_Struct(rval, IntGroup, ig);
7840 IntGroup_RaiseIfError(IntGroupAdd(ig, natoms, mol->natoms - natoms));
7847 * amend_by_symmetry(group = nil) -> IntGroup
7849 * Expand the specified part of the molecule by the given symmetry operation.
7850 * Returns an IntGroup containing the added atoms.
7853 s_Molecule_AmendBySymmetry(int argc, VALUE *argv, VALUE self)
7858 Data_Get_Struct(self, Molecule, mol);
7859 rb_scan_args(argc, argv, "01", &gval);
7861 ig = s_Molecule_AtomGroupFromValue(self, gval);
7863 MolActionCreateAndPerform(mol, gMolActionAmendBySymmetry, ig, &ig2);
7864 rval = ValueFromIntGroup(ig2);
7865 IntGroupRelease(ig2);
7871 * transform_for_symop(symop, is_cartesian = nil) -> Transform
7873 * Get the transform corresponding to the symmetry operation. The symop can either be
7874 * an integer (index of symmetry operation) or [sym, dx, dy, dz].
7875 * If is_cartesian is true, the returned transform is for cartesian coordinates.
7876 * Otherwise, the returned transform is for fractional coordinates.
7877 * Raises exception when no cell or no transform are defined.
7880 s_Molecule_TransformForSymop(int argc, VALUE *argv, VALUE self)
7886 Data_Get_Struct(self, Molecule, mol);
7887 if (mol->cell == NULL)
7888 rb_raise(rb_eMolbyError, "no unit cell is defined");
7889 if (mol->nsyms == 0)
7890 rb_raise(rb_eMolbyError, "no symmetry operation is defined");
7891 rb_scan_args(argc, argv, "11", &sval, &fval);
7892 if (rb_obj_is_kind_of(sval, rb_cNumeric)) {
7893 symop.sym = NUM2INT(rb_Integer(sval));
7894 symop.dx = symop.dy = symop.dz = 0;
7896 sval = rb_ary_to_ary(sval);
7897 if (RARRAY_LEN(sval) < 4)
7898 rb_raise(rb_eMolbyError, "missing arguments as symop; at least four integers should be given");
7899 symop.sym = NUM2INT(rb_Integer(RARRAY_PTR(sval)[0]));
7900 symop.dx = NUM2INT(rb_Integer(RARRAY_PTR(sval)[1]));
7901 symop.dy = NUM2INT(rb_Integer(RARRAY_PTR(sval)[2]));
7902 symop.dz = NUM2INT(rb_Integer(RARRAY_PTR(sval)[3]));
7904 if (symop.sym >= mol->nsyms)
7905 rb_raise(rb_eMolbyError, "index of symmetry operation (%d) is out of range", symop.sym);
7906 MoleculeGetTransformForSymop(mol, symop, &tr, (RTEST(fval) != 0));
7907 return ValueFromTransform(&tr);
7912 * symop_for_transform(transform, is_cartesian = nil) -> [sym, dx, dy, dz]
7914 * Get the symmetry operation corresponding to the given transform.
7915 * If is_cartesian is true, the given transform is for cartesian coordinates.
7916 * Otherwise, the given transform is for fractional coordinates.
7917 * Raises exception when no cell or no transform are defined.
7920 s_Molecule_SymopForTransform(int argc, VALUE *argv, VALUE self)
7927 Data_Get_Struct(self, Molecule, mol);
7928 if (mol->cell == NULL)
7929 rb_raise(rb_eMolbyError, "no unit cell is defined");
7930 if (mol->nsyms == 0)
7931 rb_raise(rb_eMolbyError, "no symmetry operation is defined");
7932 rb_scan_args(argc, argv, "11", &tval, &fval);
7933 TransformFromValue(tval, &tr);
7934 n = MoleculeGetSymopForTransform(mol, tr, &symop, (RTEST(fval) != 0));
7936 return rb_ary_new3(4, INT2NUM(symop.sym), INT2NUM(symop.dx), INT2NUM(symop.dy), INT2NUM(symop.dz));
7938 return Qnil; /* Not found */
7944 * wrap_unit_cell(group) -> Vector3D
7946 * Move the specified group so that the center of mass of the group is within the
7947 * unit cell. The offset vector is returned. If no periodic box is defined,
7948 * exception is raised.
7951 s_Molecule_WrapUnitCell(VALUE self, VALUE gval)
7956 Data_Get_Struct(self, Molecule, mol);
7957 if (mol->cell == NULL)
7958 rb_raise(rb_eMolbyError, "no unit cell is defined");
7959 ig = s_Molecule_AtomGroupFromValue(self, gval);
7960 s_Molecule_DoCenterOfMass(mol, &cv, ig);
7961 TransformVec(&v, mol->cell->rtr, &cv);
7962 if (mol->cell->flags[0])
7964 if (mol->cell->flags[1])
7966 if (mol->cell->flags[2])
7968 TransformVec(&dv, mol->cell->tr, &v);
7970 MolActionCreateAndPerform(mol, gMolActionTranslateAtoms, &dv, ig);
7971 IntGroupRelease(ig);
7972 return ValueFromVector(&dv);
7977 * find_conflicts(limit[, group1[, group2 [, ignore_exclusion]]]) -> [[n1, n2], [n3, n4], ...]
7979 * Find pairs of atoms that are within the limit distance. If group1 and group2 are given, the
7980 * first and second atom in the pair should belong to group1 and group2, respectively.
7981 * If ignore_exclusion is true, then 1-2 (bonded), 1-3, 1-4 pairs are also considered.
7984 s_Molecule_FindConflicts(int argc, VALUE *argv, VALUE self)
7987 VALUE limval, gval1, gval2, rval, igval;
7988 IntGroup *ig1, *ig2;
7989 IntGroupIterator iter1, iter2;
7995 MDExclusion *exinfo;
7998 Data_Get_Struct(self, Molecule, mol);
7999 rb_scan_args(argc, argv, "13", &limval, &gval1, &gval2, &igval);
8000 lim = NUM2DBL(rb_Float(limval));
8002 rb_raise(rb_eMolbyError, "the limit (%g) should be positive", lim);
8004 ig1 = s_Molecule_AtomGroupFromValue(self, gval1);
8006 ig1 = IntGroupNewWithPoints(0, mol->natoms, -1);
8008 ig2 = s_Molecule_AtomGroupFromValue(self, gval2);
8010 ig2 = IntGroupNewWithPoints(0, mol->natoms, -1);
8012 if (!RTEST(igval)) {
8013 /* Use the exclusion table in MDArena */
8014 if (mol->par == NULL || mol->arena == NULL || mol->arena->is_initialized == 0 || mol->needsMDRebuild) {
8015 VALUE mval = ValueFromMolecule(mol);
8016 s_RebuildMDParameterIfNecessary(mval, Qnil);
8018 exinfo = mol->arena->exinfo; /* May be NULL */
8019 exlist = mol->arena->exlist;
8024 IntGroupIteratorInit(ig1, &iter1);
8025 IntGroupIteratorInit(ig2, &iter2);
8028 while ((n[0] = IntGroupIteratorNext(&iter1)) >= 0) {
8030 ap1 = ATOM_AT_INDEX(mol->atoms, n[0]);
8032 if (exinfo != NULL) {
8033 exn1 = exinfo[n[0]].index1;
8034 exn2 = exinfo[n[0] + 1].index1;
8035 } else exn1 = exn2 = -1;
8036 IntGroupIteratorReset(&iter2);
8037 while ((n[1] = IntGroupIteratorNext(&iter2)) >= 0) {
8038 ap2 = ATOM_AT_INDEX(mol->atoms, n[1]);
8040 continue; /* Same atom */
8041 if (exinfo != NULL) {
8042 /* Look up exclusion table to exclude 1-2, 1-3, and 1-4 pairs */
8043 for (i = exn1; i < exn2; i++) {
8044 if (exlist[i] == n[1])
8048 continue; /* Should be excluded */
8050 if (MoleculeMeasureBond(mol, &r1, &(ap2->r)) < lim) {
8051 /* Is this pair already registered? */
8053 for (i = 0, ip = pairs; i < npairs; i++, ip += 2) {
8054 if ((ip[0] == n[0] && ip[1] == n[1]) || (ip[0] == n[1] && ip[1] == n[0]))
8058 /* Not registered yet */
8059 AssignArray(&pairs, &npairs, sizeof(Int) * 2, npairs, n);
8064 IntGroupIteratorRelease(&iter2);
8065 IntGroupIteratorRelease(&iter1);
8066 IntGroupRelease(ig2);
8067 IntGroupRelease(ig1);
8068 rval = rb_ary_new2(npairs);
8069 if (pairs != NULL) {
8070 for (i = 0; i < npairs; i++) {
8071 rb_ary_push(rval, rb_ary_new3(2, INT2NUM(pairs[i * 2]), INT2NUM(pairs[i * 2 + 1])));
8078 /* Calculate the transform that moves the current coordinates to the reference
8079 coordinates with least displacements. */
8081 s_Molecule_FitCoordinates_Sub(Molecule *mol, IntGroup *ig, Vector *ref, Double *weights, Transform trans)
8089 Double eigen_val[3];
8090 Vector eigen_vec[3];
8092 IntGroupIterator iter;
8094 natoms = mol->natoms;
8096 IntGroupIteratorInit(ig, &iter);
8098 /* Calculate the weighted center */
8102 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8103 ap1 = ATOM_AT_INDEX(ap, in);
8104 w1 = (weights != NULL ? weights[i] : ap1->weight);
8105 VecScaleInc(org1, ap1->r, w1);
8106 VecScaleInc(org2, ref[i], w1);
8110 VecScaleSelf(org1, w);
8111 VecScaleSelf(org2, w);
8113 /* R = sum(weight[n]^2 * x[n] * t(y[n])); */
8114 /* Matrix to diagonalize = R * tR */
8115 memset(r, 0, sizeof(Mat33));
8116 memset(q, 0, sizeof(Mat33));
8117 memset(u, 0, sizeof(Mat33));
8119 IntGroupIteratorReset(&iter);
8120 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8122 ap1 = ATOM_AT_INDEX(ap, in);
8123 w1 = (weights != NULL ? weights[i] : ap1->weight);
8125 VecSub(v1, ap1->r, org1);
8126 VecSub(v2, ref[i], org2);
8127 r[0] += w1 * v1.x * v2.x;
8128 r[1] += w1 * v1.y * v2.x;
8129 r[2] += w1 * v1.z * v2.x;
8130 r[3] += w1 * v1.x * v2.y;
8131 r[4] += w1 * v1.y * v2.y;
8132 r[5] += w1 * v1.z * v2.y;
8133 r[6] += w1 * v1.x * v2.z;
8134 r[7] += w1 * v1.y * v2.z;
8135 r[8] += w1 * v1.z * v2.z;
8138 for (i = 0; i < 9; i++)
8140 for (i = 0; i < 3; i++) {
8141 for (j = 0; j < 3; j++) {
8142 for (k = 0; k < 3; k++) {
8143 q[i+j*3] += r[i+k*3] * r[j+k*3];
8148 if (MatrixSymDiagonalize(q, eigen_val, eigen_vec) != 0) {
8149 IntGroupIteratorRelease(&iter);
8150 return -1.0; /* Cannot determine the eigenvector */
8153 /* s[i] = tR * v[i] / sqrt(eigenval[i]) */
8154 /* U = s0*t(v0) + s1*t(v1) + s2*t(v2) */
8155 MatrixTranspose(r, r);
8156 for (i = 0; i < 3; i++) {
8157 MatrixVec(&s[i], r, &eigen_vec[i]);
8158 w1 = 1.0 / sqrt(eigen_val[i]);
8159 VecScaleSelf(s[i], w1);
8161 for (k = 0; k < 3; k++) {
8162 u[0] += s[k].x * eigen_vec[k].x;
8163 u[1] += s[k].y * eigen_vec[k].x;
8164 u[2] += s[k].z * eigen_vec[k].x;
8165 u[3] += s[k].x * eigen_vec[k].y;
8166 u[4] += s[k].y * eigen_vec[k].y;
8167 u[5] += s[k].z * eigen_vec[k].y;
8168 u[6] += s[k].x * eigen_vec[k].z;
8169 u[7] += s[k].y * eigen_vec[k].z;
8170 u[8] += s[k].z * eigen_vec[k].z;
8173 /* y = U*(x - org1) + org2 = U*x + (org2 - U*org1) */
8174 MatrixVec(&org1, u, &org1);
8176 for (i = 0; i < 9; i++)
8182 /* Calculate rmsd */
8183 IntGroupIteratorReset(&iter);
8185 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8187 ap1 = ATOM_AT_INDEX(ap, in);
8188 TransformVec(&tv, trans, &ap1->r);
8190 w += VecLength2(tv);
8193 IntGroupIteratorRelease(&iter);
8199 * fit_coordinates(group, ref, weight = nil) -> [transform, rmsd]
8201 * Calculate the transform to fit the given group to the set of reference coordinates.
8202 * The reference coordinates ref is given as either a frame number, an array of
8203 * Vector3Ds or arrays, or an LAMatrix. Weight can be optionally given as an array
8204 * of numbers or an LAMatrix. If weight is not given, the atomic weights are used.
8205 * Return values are the transform (that converts the present coordinates to the
8206 * target coordinates) and root mean square deviation (without weight).
8209 s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
8213 VALUE gval, rval, wval;
8215 IntGroupIterator iter;
8216 int nn, errno, i, j, in, status;
8218 Double *weights, dval[3];
8221 Data_Get_Struct(self, Molecule, mol);
8222 rb_scan_args(argc, argv, "21", &gval, &rval, &wval);
8224 ig = IntGroupNewWithPoints(0, mol->natoms, -1);
8226 ig = IntGroupFromValue(gval);
8227 if (ig == NULL || (nn = IntGroupGetCount(ig)) == 0) {
8228 IntGroupRelease(ig);
8229 rb_raise(rb_eMolbyError, "atom group is not given correctly");
8231 ref = (Vector *)calloc(sizeof(Vector), nn);
8232 weights = (Double *)calloc(sizeof(Double), nn);
8233 IntGroupIteratorInit(ig, &iter);
8234 if (rb_obj_is_kind_of(rval, rb_cNumeric)) {
8235 int fn = NUM2INT(rb_Integer(rval));
8236 if (fn < 0 || fn >= MoleculeGetNumberOfFrames(mol)) {
8241 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8242 ap = ATOM_AT_INDEX(mol->atoms, in);
8243 if (fn < ap->nframes)
8244 ref[i] = ap->frames[fn];
8245 else ref[i] = ap->r;
8247 } else if (rb_obj_is_kind_of(rval, rb_cLAMatrix)) {
8248 LAMatrix *m = LAMatrixFromValue(rval, NULL, 0, 0);
8249 if (m->row * m->column < nn * 3) {
8253 for (i = 0; i < nn; i++) {
8254 ref[i].x = m->data[i * 3];
8255 ref[i].y = m->data[i * 3 + 1];
8256 ref[i].z = m->data[i * 3 + 2];
8260 rval = rb_protect(rb_ary_to_ary, rval, &status);
8265 if (RARRAY_LEN(rval) < nn) {
8269 if (rb_obj_is_kind_of((RARRAY_PTR(rval))[0], rb_cNumeric)) {
8270 /* Array of 3*nn numbers */
8271 if (RARRAY_LEN(rval) < nn * 3) {
8275 for (i = 0; i < nn; i++) {
8276 for (j = 0; j < 3; j++) {
8277 aval = rb_protect(rb_Float, (RARRAY_PTR(rval))[i * 3 + j], &status);
8282 dval[j] = NUM2DBL(aval);
8289 /* Array of nn Vector3Ds or Arrays */
8290 for (i = 0; i < nn; i++) {
8291 aval = (RARRAY_PTR(rval))[i];
8292 if (rb_obj_is_kind_of(aval, rb_cVector3D)) {
8293 VectorFromValue(aval, &ref[i]);
8295 aval = rb_protect(rb_ary_to_ary, aval, &status);
8300 if (RARRAY_LEN(aval) < 3) {
8305 for (j = 0; j < 3; j++) {
8306 VALUE aaval = rb_protect(rb_Float, (RARRAY_PTR(aval))[j], &status);
8311 dval[j] = NUM2DBL(aaval);
8321 /* Use atomic weights */
8322 IntGroupIteratorReset(&iter);
8323 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8324 ap = ATOM_AT_INDEX(mol->atoms, in);
8325 weights[i] = ap->weight;
8328 wval = rb_protect(rb_ary_to_ary, wval, &status);
8333 if (RARRAY_LEN(wval) < nn) {
8337 for (i = 0; i < nn; i++) {
8338 VALUE wwval = rb_protect(rb_Float, (RARRAY_PTR(wval))[i], &status);
8343 weights[i] = NUM2DBL(wwval);
8346 dval[0] = s_Molecule_FitCoordinates_Sub(mol, ig, ref, weights, tr);
8353 IntGroupIteratorRelease(&iter);
8357 return rb_ary_new3(2, ValueFromTransform(&tr), rb_float_new(dval[0]));
8358 } else if (errno == 1) {
8359 rb_raise(rb_eMolbyError, "frame index (%d) is out of range", status);
8360 } else if (errno == 2) {
8361 rb_raise(rb_eMolbyError, "insufficient number of reference coordinates");
8362 } else if (errno == 3) {
8363 rb_jump_tag(status);
8364 } else if (errno == 4) {
8365 rb_raise(rb_eMolbyError, "less than 3 elements for index %d of reference coordinates", status);
8366 } else if (errno == 5) {
8367 rb_raise(rb_eMolbyError, "insufficient number of weight values");
8368 } else if (errno == 6) {
8369 rb_raise(rb_eMolbyError, "matrix calculation failed during coordinate fitting");
8371 return Qnil; /* Not reached */
8378 * Refresh the display if this molecule is bound to a view. Otherwise do nothing.
8381 s_Molecule_Display(VALUE self)
8384 Data_Get_Struct(self, Molecule, mol);
8385 if (mol->mview != NULL)
8386 MainViewCallback_display(mol->mview);
8394 * Make the window frontmost if this molecule is bound to a view. Otherwise do nothing.
8397 s_Molecule_MakeFront(VALUE self)
8400 Data_Get_Struct(self, Molecule, mol);
8401 if (mol->mview != NULL)
8402 MainViewCallback_makeFront(mol->mview);
8408 * update_enabled? -> bool
8410 * Returns true if screen update is enabled; otherwise no.
8413 s_Molecule_UpdateEnabled(VALUE self)
8416 Data_Get_Struct(self, Molecule, mol);
8417 if (mol->mview != NULL && !mol->mview->freezeScreen)
8424 * update_enabled = bool
8426 * Enable or disable screen update. This is effective for automatic update on modification.
8427 * Explicit call to molecule.display() always updates the screen.
8430 s_Molecule_SetUpdateEnabled(VALUE self, VALUE val)
8433 Data_Get_Struct(self, Molecule, mol);
8434 val = ((val != Qfalse && val != Qnil) ? Qtrue : Qfalse);
8435 if (mol->mview != NULL)
8436 mol->mview->freezeScreen = (val == Qfalse);
8444 * show_unitcell(bool)
8445 * show_unitcell = bool
8447 * Set the flag whether to show the unit cell. If no argument is given, the
8448 * current flag is returned.
8451 s_Molecule_ShowUnitCell(int argc, VALUE *argv, VALUE self)
8454 Data_Get_Struct(self, Molecule, mol);
8455 if (mol->mview == NULL)
8458 mol->mview->showUnitCell = (RTEST(argv[0]) != 0);
8459 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8461 return (mol->mview->showUnitCell ? Qtrue : Qfalse);
8467 * show_hydrogens(bool)
8468 * show_hydrogens = bool
8470 * Set the flag whether to show the hydrogen atoms. If no argument is given, the
8471 * current flag is returned.
8474 s_Molecule_ShowHydrogens(int argc, VALUE *argv, VALUE self)
8477 Data_Get_Struct(self, Molecule, mol);
8478 if (mol->mview == NULL)
8481 mol->mview->showHydrogens = (RTEST(argv[0]) != 0);
8482 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8484 return (mol->mview->showHydrogens ? Qtrue : Qfalse);
8490 * show_dummy_atoms(bool)
8491 * show_dummy_atoms = bool
8493 * Set the flag whether to show the dummy atoms. If no argument is given, the
8494 * current flag is returned.
8497 s_Molecule_ShowDummyAtoms(int argc, VALUE *argv, VALUE self)
8500 Data_Get_Struct(self, Molecule, mol);
8501 if (mol->mview == NULL)
8504 mol->mview->showDummyAtoms = (RTEST(argv[0]) != 0);
8505 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8507 return (mol->mview->showDummyAtoms ? Qtrue : Qfalse);
8513 * show_expanded(bool)
8514 * show_expanded = bool
8516 * Set the flag whether to show the expanded atoms. If no argument is given, the
8517 * current flag is returned.
8520 s_Molecule_ShowExpanded(int argc, VALUE *argv, VALUE self)
8523 Data_Get_Struct(self, Molecule, mol);
8524 if (mol->mview == NULL)
8527 mol->mview->showExpandedAtoms = (RTEST(argv[0]) != 0);
8528 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8530 return (mol->mview->showExpandedAtoms ? Qtrue : Qfalse);
8536 * show_ellipsoids(bool)
8537 * show_ellipsoids = bool
8539 * Set the flag whether to show the thermal ellipsoids. If no argument is given, the
8540 * current flag is returned.
8543 s_Molecule_ShowEllipsoids(int argc, VALUE *argv, VALUE self)
8546 Data_Get_Struct(self, Molecule, mol);
8547 if (mol->mview == NULL)
8550 mol->mview->showEllipsoids = (RTEST(argv[0]) != 0);
8551 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8553 return (mol->mview->showEllipsoids ? Qtrue : Qfalse);
8558 * is_atom_visible(index) -> Boolean
8560 * Check is an atom is visible. It examines the atom attribute (ap->exflags & kAtomHiddenFlag)
8561 * as well as the molecule attributes (showHydrogens, etc.)
8564 s_Molecule_IsAtomVisible(VALUE self, VALUE ival)
8569 Data_Get_Struct(self, Molecule, mol);
8570 idx = s_Molecule_AtomIndexFromValue(mol, ival);
8571 if (idx < 0 || idx >= mol->natoms)
8573 ap = ATOM_AT_INDEX(mol->atoms, idx);
8574 if (mol->mview != NULL) {
8575 if (mol->mview->showHydrogens == 0 && ap->atomicNumber == 1)
8577 if (mol->mview->showExpandedAtoms == 0 && SYMOP_ALIVE(ap->symop))
8579 if (mol->mview->showDummyAtoms == 0 && ap->atomicNumber == 0)
8582 return ((ap->exflags & kAtomHiddenFlag) != 0 ? Qfalse : Qtrue);
8587 * show_graphite -> Integer
8588 * show_graphite = Integer
8589 * show_graphite = boolean
8591 * Set whether to show the graphite plane. If the argument is positive, it also indicates the
8592 * number of rings to display for each direction.
8593 * If the argument is boolean, only the show/hide flag is set.
8596 s_Molecule_ShowGraphite(int argc, VALUE *argv, VALUE self)
8599 Data_Get_Struct(self, Molecule, mol);
8600 if (mol->mview == NULL)
8603 if (argv[0] == Qnil || argv[0] == Qfalse)
8604 mol->mview->showGraphiteFlag = 0;
8605 else if (argv[0] == Qtrue)
8606 mol->mview->showGraphiteFlag = 1;
8608 int n = NUM2INT(rb_Integer(argv[0]));
8610 rb_raise(rb_eMolbyError, "The argument must be non-negative integer");
8611 mol->mview->showGraphite = n;
8613 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8615 return INT2NUM(mol->mview->showGraphite);
8620 * show_graphite? -> boolean
8622 * Return whether the graphite is set visible or not.
8625 s_Molecule_ShowGraphiteFlag(VALUE self)
8628 Data_Get_Struct(self, Molecule, mol);
8629 if (mol->mview == NULL)
8631 return (mol->mview->showGraphiteFlag ? Qtrue : Qfalse);
8636 * show_periodic_image -> [amin, amax, bmin, bmax, cmin, cmax]
8637 * show_periodic_image = [amin, amax, bmin, bmax, cmin, cmax]
8638 * show_periodic_image = boolean
8640 * Set to show the periodic image of the atoms. If the unit cell is not defined, the values are
8641 * set but no visual effects are observed.
8642 * If the argument is boolean, only the show/hide flag is modified.
8645 s_Molecule_ShowPeriodicImage(int argc, VALUE *argv, VALUE self)
8651 Data_Get_Struct(self, Molecule, mol);
8652 if (mol->mview == NULL)
8654 rb_scan_args(argc, argv, "01", &val);
8656 /* Change current settings */
8657 if (val == Qnil || val == Qfalse)
8658 mol->mview->showPeriodicImageFlag = 0;
8659 else if (val == Qtrue)
8660 mol->mview->showPeriodicImageFlag = 1;
8662 val = rb_ary_to_ary(val);
8663 for (i = 0; i < 6; i++) {
8664 if (i < RARRAY_LEN(val))
8665 ival[i] = NUM2INT(rb_Integer(RARRAY_PTR(val)[i]));
8667 if (ival[0] > 0 || ival[1] < 0 || ival[2] > 0 || ival[3] < 0 || ival[4] > 0 || ival[5] < 0)
8668 rb_raise(rb_eMolbyError, "bad arguments");
8669 for (i = 0; i < 6; i++)
8670 mol->mview->showPeriodicImage[i] = ival[i];
8672 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8675 for (i = 0; i < 6; i++)
8676 rb_ary_push(val, INT2NUM(mol->mview->showPeriodicImage[i]));
8682 * show_periodic_image? -> boolean
8684 * Return whether the periodic images are set to visible or not. This flag is
8685 * independent from the show_periodic_image settings.
8688 s_Molecule_ShowPeriodicImageFlag(VALUE self)
8691 Data_Get_Struct(self, Molecule, mol);
8692 if (mol->mview == NULL)
8694 return (mol->mview->showPeriodicImageFlag ? Qtrue : Qfalse);
8703 * Set the flag whether to draw the model in line mode. If no argument is given, the
8704 * current flag is returned.
8707 s_Molecule_LineMode(int argc, VALUE *argv, VALUE self)
8710 Data_Get_Struct(self, Molecule, mol);
8711 if (mol->mview == NULL)
8714 mol->mview->lineMode = (RTEST(argv[0]) != 0);
8715 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8717 return (mol->mview->lineMode ? Qtrue : Qfalse);
8724 * Resize the model drawing to fit in the window.
8727 s_Molecule_ResizeToFit(VALUE self)
8730 Data_Get_Struct(self, Molecule, mol);
8731 if (mol->mview != NULL)
8732 MainView_resizeToFit(mol->mview);
8738 * get_view_rotation -> [[ax, ay, az], angle]
8740 * Get the current rotation for the view. Angle is in degree, not radian.
8743 s_Molecule_GetViewRotation(VALUE self)
8748 Data_Get_Struct(self, Molecule, mol);
8749 if (mol->mview == NULL)
8751 TrackballGetRotate(mol->mview->track, f);
8752 f[0] = -f[0]; /* Convert to left-handed screw (to be consistent with Transform) */
8756 return rb_ary_new3(2, ValueFromVector(&v), rb_float_new(f[0]));
8761 * get_view_scale -> float
8763 * Get the current scale for the view.
8766 s_Molecule_GetViewScale(VALUE self)
8769 Data_Get_Struct(self, Molecule, mol);
8770 if (mol->mview == NULL)
8772 return rb_float_new(TrackballGetScale(mol->mview->track));
8777 * get_view_center -> Vector
8779 * Get the current center point of the view.
8782 s_Molecule_GetViewCenter(VALUE self)
8787 Data_Get_Struct(self, Molecule, mol);
8788 if (mol->mview == NULL)
8790 TrackballGetTranslate(mol->mview->track, f);
8791 v.x = -f[0] * mol->mview->dimension;
8792 v.y = -f[1] * mol->mview->dimension;
8793 v.z = -f[2] * mol->mview->dimension;
8794 return ValueFromVector(&v);
8799 * set_view_rotation([ax, ay, az], angle) -> self
8801 * Set the current rotation for the view. Angle is in degree, not radian.
8804 s_Molecule_SetViewRotation(VALUE self, VALUE aval, VALUE angval)
8809 Data_Get_Struct(self, Molecule, mol);
8810 if (mol->mview == NULL)
8812 VectorFromValue(aval, &v);
8813 if (NormalizeVec(&v, &v))
8814 rb_raise(rb_eMolbyError, "Cannot normalize nearly zero vector");
8818 f[0] = -NUM2DBL(rb_Float(angval));
8819 TrackballSetRotate(mol->mview->track, f);
8820 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8826 * set_view_scale(scale) -> self
8828 * Set the current scale for the view.
8831 s_Molecule_SetViewScale(VALUE self, VALUE aval)
8834 Data_Get_Struct(self, Molecule, mol);
8835 if (mol->mview == NULL)
8837 TrackballSetScale(mol->mview->track, NUM2DBL(rb_Float(aval)));
8838 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8844 * set_view_center(vec) -> self
8846 * Set the current center point of the view.
8849 s_Molecule_SetViewCenter(VALUE self, VALUE aval)
8854 Data_Get_Struct(self, Molecule, mol);
8855 if (mol->mview == NULL)
8857 VectorFromValue(aval, &v);
8858 f[0] = -v.x / mol->mview->dimension;
8859 f[1] = -v.y / mol->mview->dimension;
8860 f[2] = -v.z / mol->mview->dimension;
8861 TrackballSetTranslate(mol->mview->track, f);
8862 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8868 * set_background_color(red, green, blue)
8870 * Set the background color of the model window.
8873 s_Molecule_SetBackgroundColor(int argc, VALUE *argv, VALUE self)
8876 Data_Get_Struct(self, Molecule, mol);
8877 if (mol->mview != NULL) {
8878 VALUE rval, gval, bval;
8879 rb_scan_args(argc, argv, "30", &rval, &gval, &bval);
8880 MainView_setBackgroundColor(mol->mview, NUM2DBL(rb_Float(rval)), NUM2DBL(rb_Float(gval)), NUM2DBL(rb_Float(bval)));
8887 * create_graphic(kind, color, points, fill = nil) -> integer
8889 * Create a new graphic object.
8890 * kind: a symbol representing the kind of the graphic. :line, :poly, :cylinder, :cone, :ellipsoid
8891 * color: an array of 3 (rgb) or 4 (rgba) floating numbers
8892 * points: an array of Vectors
8896 s_Molecule_CreateGraphic(int argc, VALUE *argv, VALUE self)
8902 VALUE kval, cval, pval, fval;
8903 Data_Get_Struct(self, Molecule, mol);
8904 if (mol->mview == NULL)
8905 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
8906 rb_scan_args(argc, argv, "31", &kval, &cval, &pval, &fval);
8907 kval = rb_obj_as_string(kval);
8908 memset(&g, 0, sizeof(g));
8910 p = RSTRING_PTR(kval);
8911 if (strcmp(p, "line") == 0)
8912 g.kind = kMainViewGraphicLine;
8913 else if (strcmp(p, "poly") == 0)
8914 g.kind = kMainViewGraphicPoly;
8915 else if (strcmp(p, "cylinder") == 0)
8916 g.kind = kMainViewGraphicCylinder;
8917 else if (strcmp(p, "cone") == 0)
8918 g.kind = kMainViewGraphicCone;
8919 else if (strcmp(p, "ellipsoid") == 0)
8920 g.kind = kMainViewGraphicEllipsoid;
8921 else rb_raise(rb_eMolbyError, "unknown graphic object type: %s", p);
8922 g.closed = (RTEST(fval) ? 1 : 0);
8923 cval = rb_ary_to_ary(cval);
8924 n = RARRAY_LEN(cval);
8925 if (n < 3 || n >= 5)
8926 rb_raise(rb_eArgError, "the color should have 3 or 4 elements");
8929 for (i = 0; i < n; i++)
8930 g.rgba[i] = NUM2DBL(rb_Float(RARRAY_PTR(cval)[i]));
8931 pval = rb_ary_to_ary(pval);
8932 n = RARRAY_LEN(pval);
8933 ni = -1; /* If this is non-negative, then ni-th control point is [number, 0, 0] */
8935 rb_raise(rb_eArgError, "no control points are given");
8937 case kMainViewGraphicLine:
8939 rb_raise(rb_eArgError, "the line object must have at least two control points");
8941 case kMainViewGraphicPoly:
8943 rb_raise(rb_eArgError, "the polygon object must have at least three control points");
8945 case kMainViewGraphicCylinder:
8946 case kMainViewGraphicCone:
8948 rb_raise(rb_eArgError, "the %s object must have two control points and one number (radius)", (g.kind == kMainViewGraphicCylinder ? "cylinder" : "cone"));
8951 case kMainViewGraphicEllipsoid:
8955 rb_raise(rb_eArgError, "the ellipsoid object must have either one point and one number (radius) or four points (center and three main axes)");
8958 NewArray(&g.points, &g.npoints, sizeof(GLfloat) * 3, n);
8959 for (i = 0; i < n; i++) {
8962 v.x = NUM2DBL(rb_Float(RARRAY_PTR(pval)[i]));
8965 VectorFromValue(RARRAY_PTR(pval)[i], &v);
8967 g.points[i * 3] = v.x;
8968 g.points[i * 3 + 1] = v.y;
8969 g.points[i * 3 + 2] = v.z;
8971 if (g.kind == kMainViewGraphicEllipsoid && ni == 1) {
8973 AssignArray(&g.points, &g.npoints, sizeof(GLfloat) * 3, 4, NULL);
8974 g.points[6] = g.points[8] = g.points[9] = g.points[10] = 0;
8975 g.points[7] = g.points[11] = g.points[3];
8977 MainView_insertGraphic(mol->mview, -1, &g);
8978 return INT2NUM(mol->mview->ngraphics - 1);
8983 * remove_graphic(index) -> integer
8985 * Remove a graphic object.
8988 s_Molecule_RemoveGraphic(VALUE self, VALUE ival)
8992 Data_Get_Struct(self, Molecule, mol);
8993 if (mol->mview == NULL)
8994 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
8995 i = NUM2INT(rb_Integer(ival));
8996 if (i < 0 || i >= mol->mview->ngraphics)
8997 rb_raise(rb_eArgError, "graphic index is out of range");
8998 MainView_removeGraphic(mol->mview, i);
9004 * ngraphics -> integer
9006 * Get the number of graphic objects.
9009 s_Molecule_NGraphics(VALUE self)
9012 Data_Get_Struct(self, Molecule, mol);
9013 if (mol->mview == NULL)
9014 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9015 return INT2NUM(mol->mview->ngraphics);
9020 * set_graphic_point(graphic_index, point_index, new_value) -> new_value
9022 * Change the point_index-th control point of graphic_index-th graphic object
9026 s_Molecule_SetGraphicPoint(VALUE self, VALUE gval, VALUE pval, VALUE nval)
9028 MainViewGraphic *gp;
9032 Data_Get_Struct(self, Molecule, mol);
9033 if (mol->mview == NULL)
9034 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9035 index = NUM2INT(rb_Integer(gval));
9036 if (index < 0 || index >= mol->mview->ngraphics)
9037 rb_raise(rb_eArgError, "the graphic index is out of range");
9038 gp = mol->mview->graphics + index;
9039 index = NUM2INT(rb_Integer(pval));
9040 if (index < 0 || index >= gp->npoints)
9041 rb_raise(rb_eArgError, "the point index is out of range");
9042 if (rb_obj_is_kind_of(nval, rb_cNumeric)) {
9043 if ((gp->kind == kMainViewGraphicCylinder || gp->kind == kMainViewGraphicCone) && index == 2) {
9044 v.x = NUM2DBL(rb_Float(nval));
9046 } else if (gp->kind == kMainViewGraphicEllipsoid && index == 1) {
9047 gp->points[3] = gp->points[7] = gp->points[11] = NUM2DBL(rb_Float(nval));
9048 gp->points[4] = gp->points[5] = gp->points[6] = gp->points[8] = gp->points[9] = gp->points[10] = 0;
9050 } else rb_raise(rb_eArgError, "the argument must be an array-like object");
9053 v.x = kInvalidFloat;
9055 } else VectorFromValue(nval, &v);
9057 gp->points[index * 3] = v.x;
9058 gp->points[index * 3 + 1] = v.y;
9059 gp->points[index * 3 + 2] = v.z;
9060 MoleculeCallback_notifyModification(mol, 0);
9066 * set_graphic_color(graphic_index, new_value) -> new_value
9068 * Change the color of graphic_index-th graphic object
9072 s_Molecule_SetGraphicColor(VALUE self, VALUE gval, VALUE cval)
9074 MainViewGraphic *gp;
9077 Data_Get_Struct(self, Molecule, mol);
9078 if (mol->mview == NULL)
9079 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9080 index = NUM2INT(rb_Integer(gval));
9081 if (index < 0 || index >= mol->mview->ngraphics)
9082 rb_raise(rb_eArgError, "the graphic index is out of range");
9083 gp = mol->mview->graphics + index;
9084 cval = rb_ary_to_ary(cval);
9085 n = RARRAY_LEN(cval);
9086 if (n != 3 && n != 4)
9087 rb_raise(rb_eArgError, "the color argument must have 3 or 4 numbers");
9088 for (index = 0; index < n; index++) {
9089 gp->rgba[index] = NUM2DBL(rb_Float(RARRAY_PTR(cval)[index]));
9093 MoleculeCallback_notifyModification(mol, 0);
9099 * show_graphic(graphic_index) -> self
9101 * Enable the visible flag of the graphic_index-th graphic object
9105 s_Molecule_ShowGraphic(VALUE self, VALUE gval)
9107 MainViewGraphic *gp;
9110 Data_Get_Struct(self, Molecule, mol);
9111 if (mol->mview == NULL)
9112 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9113 index = NUM2INT(rb_Integer(gval));
9114 if (index < 0 || index >= mol->mview->ngraphics)
9115 rb_raise(rb_eArgError, "the graphic index is out of range");
9116 gp = mol->mview->graphics + index;
9118 MoleculeCallback_notifyModification(mol, 0);
9124 * hide_graphic(graphic_index) -> self
9126 * Disable the visible flag of the graphic_index-th graphic object
9130 s_Molecule_HideGraphic(VALUE self, VALUE gval)
9132 MainViewGraphic *gp;
9135 Data_Get_Struct(self, Molecule, mol);
9136 if (mol->mview == NULL)
9137 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9138 index = NUM2INT(rb_Integer(gval));
9139 if (index < 0 || index >= mol->mview->ngraphics)
9140 rb_raise(rb_eArgError, "the graphic index is out of range");
9141 gp = mol->mview->graphics + index;
9143 MoleculeCallback_notifyModification(mol, 0);
9151 * Show the string in the info text box.
9154 s_Molecule_ShowText(VALUE self, VALUE arg)
9157 Data_Get_Struct(self, Molecule, mol);
9158 if (mol->mview != NULL)
9159 MainViewCallback_drawInfoText(mol->mview, StringValuePtr(arg));
9165 * md_arena -> MDArena
9167 * Returns the MDArena object associated to this molecule. If no MDArena is associated to
9168 * this molecule, a new arena is created.
9171 s_Molecule_MDArena(VALUE self)
9175 Data_Get_Struct(self, Molecule, mol);
9176 if (mol->arena == NULL)
9178 retval = ValueFromMDArena(mol->arena);
9184 * set_parameter_attr(type, index, key, value, src) -> value
9186 * This method is used only internally.
9189 s_Molecule_SetParameterAttr(VALUE self, VALUE tval, VALUE ival, VALUE kval, VALUE vval, VALUE sval)
9191 /* This method is called from MolAction to change a MM parameter attribute. */
9196 Data_Get_Struct(self, Molecule, mol);
9197 pval = ValueFromMoleculeWithParameterTypeAndIndex(mol, FIX2INT(tval), NUM2INT(ival));
9198 vval = s_ParameterRef_SetAttr(pval, kval, vval);
9200 /* This is the special part of this method; it allows modification of the src field. */
9201 /* (ParameterRef#set_attr sets 0 to the src field) */
9202 Data_Get_Struct(pval, ParameterRef, pref);
9203 up = ParameterRefGetPar(pref);
9204 up->bond.src = FIX2INT(sval);
9211 * parameter -> Parameter
9213 * Get the local parameter of this molecule. If not defined, returns nil.
9216 s_Molecule_Parameter(VALUE self)
9219 Data_Get_Struct(self, Molecule, mol);
9220 /* if (mol->par == NULL)
9222 return s_NewParameterValueFromValue(self);
9227 * selectedMO -> IntGroup
9229 * Returns a group of selected mo in the "MO Info" table. If the MO info table
9230 * is not selected, returns nil. If the MO info table is selected but no MOs
9231 * are selected, returns an empty IntGroup. The numbers in the table are 1-based.
9234 s_Molecule_SelectedMO(VALUE self)
9239 Data_Get_Struct(self, Molecule, mol);
9240 if (mol->mview == NULL)
9242 ig = MainView_selectedMO(mol->mview);
9245 IntGroupOffset(ig, 1);
9246 val = ValueFromIntGroup(ig);
9247 IntGroupRelease(ig);
9253 * default_MO_grid(npoints = 80*80*80) -> [origin, dx, dy, dz, nx, ny, nz]
9255 * Returns a default MO grid for cube file generation. Origin: Vector, dx, dy, dz: float, nx, ny, nz: integer.
9256 * If the molecule does not contain a basis set information, then returns nil.
9259 s_Molecule_GetDefaultMOGrid(int argc, VALUE *argv, VALUE self)
9262 Vector o, dx, dy, dz;
9265 Int npoints = 80 * 80 * 80;
9266 Data_Get_Struct(self, Molecule, mol);
9267 if (mol->bset == NULL)
9269 rb_scan_args(argc, argv, "01", &nval);
9271 npoints = NUM2INT(rb_Integer(nval));
9272 if (MoleculeGetDefaultMOGrid(mol, npoints, &o, &dx, &dy, &dz, &nx, &ny, &nz) != 0)
9274 return rb_ary_new3(7, ValueFromVector(&o), rb_float_new(VecLength(dx)), rb_float_new(VecLength(dy)), rb_float_new(VecLength(dz)), INT2NUM(nx), INT2NUM(ny), INT2NUM(nz));
9278 s_Cubegen_callback(double progress, void *ref)
9280 MyAppCallback_setProgressValue(progress);
9281 if (MyAppCallback_checkInterrupt())
9288 * cubegen(fname, mo, npoints=1000000 [, iflag [, beta]])
9289 * cubegen(fname, mo, origin, dx, dy, dz, nx, ny, nz [, iflag [, beta]])
9291 * Calculate the molecular orbital with number mo and create a 'cube' file.
9292 * In the first form, the cube size is estimated from the atomic coordinates. In the
9293 * second form, the cube dimension is explicitly given.
9294 * Returns fname when successful, nil otherwise.
9295 * If iflag is non-false, then MyAppCallback_checkInterrupt() is periodically called during calculation.
9296 * If beta is non-false, then the beta MO is calculated (valid only for UHF MO)
9297 * (The interrupt monitoring thread is disabled, so as not to enter Ruby interpreter during calculation)
9300 s_Molecule_Cubegen(int argc, VALUE *argv, VALUE self)
9302 VALUE fval, mval, oval, dxval, dyval, dzval, nxval, nyval, nzval, ival, bval;
9304 Int mono, nx, ny, nz, npoints;
9305 Vector o, dx, dy, dz;
9308 Data_Get_Struct(self, Molecule, mol);
9309 if (mol->bset == NULL)
9310 rb_raise(rb_eMolbyError, "The molecule does not contain MO information");
9311 rb_scan_args(argc, argv, "29", &fval, &mval, &oval, &dxval, &dyval, &dzval, &nxval, &nyval, &nzval, &ival, &bval);
9313 /* Set up parameters */
9314 mono = NUM2INT(rb_Integer(mval));
9315 if (mono <= 0 || mono > mol->bset->ncomps)
9316 rb_raise(rb_eMolbyError, "The MO number (%d) is out of range (should be 1..%d)", mono, mol->bset->ncomps);
9318 if (mol->bset->rflag != 0)
9319 rb_raise(rb_eMolbyError, "Beta MO is requested but not present");
9320 mono += mol->bset->ncomps;
9323 if (oval == Qnil || dxval == Qnil || dyval == Qnil) {
9324 /* Automatic grid formation */
9326 npoints = NUM2INT(rb_Integer(oval));
9330 else if (npoints < 8)
9331 rb_raise(rb_eMolbyError, "The number of points (%d) should be at least 8", npoints);
9332 if (MoleculeGetDefaultMOGrid(mol, npoints, &o, &dx, &dy, &dz, &nx, &ny, &nz) != 0)
9333 rb_raise(rb_eMolbyError, "Cannot determine cube grids");
9337 VectorFromValue(oval, &o);
9338 if (TYPE(dxval) == T_ARRAY || rb_obj_is_kind_of(dxval, rb_cVector3D))
9339 VectorFromValue(dxval, &dx);
9341 dx.x = NUM2DBL(rb_Float(dxval));
9344 if (TYPE(dyval) == T_ARRAY || rb_obj_is_kind_of(dyval, rb_cVector3D))
9345 VectorFromValue(dyval, &dy);
9347 dy.y = NUM2DBL(rb_Float(dyval));
9350 if (TYPE(dzval) == T_ARRAY || rb_obj_is_kind_of(dzval, rb_cVector3D))
9351 VectorFromValue(dzval, &dz);
9353 dz.z = NUM2DBL(rb_Float(dzval));
9356 nx = NUM2INT(rb_Integer(nxval));
9357 ny = NUM2INT(rb_Integer(nyval));
9358 nz = NUM2INT(rb_Integer(nzval));
9359 if (nx <= 0 || ny <= 0 || nz <= 0)
9360 rb_raise(rb_eMolbyError, "The number of points (%d,%d,%d) should be positive integers", nx, ny, nz);
9361 else if (nx > 10000 || ny > 10000 || nz > 10000 || nx * ny * nz > 100000000)
9362 rb_raise(rb_eMolbyError, "The number of points (%d,%d,%d) seem to be too large; please keep them less than 10000 and nx*ny*nz < 100000000", nx, ny, nz);
9366 index = MoleculeCalcMO(mol, mono, &o, &dx, &dy, &dz, nx, ny, nz, (RTEST(ival) ? s_Cubegen_callback : NULL), NULL);
9370 rb_raise(rb_eMolbyError, "Cannot calculate MO %d", mono);
9372 /* Output to file */
9373 MoleculeCallback_displayName(mol, buf, sizeof buf);
9374 n = MoleculeOutputCube(mol, index, FileStringValuePtr(fval), buf);
9376 rb_raise(rb_eMolbyError, "Cannot output MO cube to file %p", FileStringValuePtr(fval));
9378 /* Discard the cube */
9379 MoleculeClearCubeAtIndex(mol, index);
9387 * Get the number of electrostatic potential info.
9390 s_Molecule_NElpots(VALUE self)
9393 Data_Get_Struct(self, Molecule, mol);
9394 return INT2NUM(mol->nelpots);
9401 * Get the electrostatic potential info at the given index. If present, then the
9402 * return value is [Vector, Float] (position and potential). If not present, then
9406 s_Molecule_Elpot(VALUE self, VALUE ival)
9410 Data_Get_Struct(self, Molecule, mol);
9411 idx = NUM2INT(rb_Integer(ival));
9412 if (idx < 0 || idx >= mol->nelpots)
9414 return rb_ary_new3(2, ValueFromVector(&mol->elpots[idx].pos), rb_float_new(mol->elpots[idx].esp));
9419 * add_gaussian_orbital_shell(sym, nprims, atom_index)
9421 * To be used internally. Add a gaussian orbital shell with symmetry code, number of primitives,
9422 * and the corresponding atom index. Symmetry code: 0, S-type; 1, P-type; -1, SP-type; 2, D-type;
9426 s_Molecule_AddGaussianOrbitalShell(VALUE self, VALUE symval, VALUE npval, VALUE aval)
9429 int sym, nprims, a_idx, n;
9430 Data_Get_Struct(self, Molecule, mol);
9431 sym = NUM2INT(rb_Integer(symval));
9432 nprims = NUM2INT(rb_Integer(npval));
9433 a_idx = NUM2INT(rb_Integer(aval));
9434 n = MoleculeAddGaussianOrbitalShell(mol, sym, nprims, a_idx);
9436 rb_raise(rb_eMolbyError, "Molecule is emptry");
9438 rb_raise(rb_eMolbyError, "Low memory");
9440 rb_raise(rb_eMolbyError, "Unknown orbital type");
9442 rb_raise(rb_eMolbyError, "Unknown error");
9448 * add_gaussian_primitive_coefficients(exponent, contraction, contraction_sp)
9450 * To be used internally. Add a gaussian primitive coefficients.
9453 s_Molecule_AddGaussianPrimitiveCoefficients(VALUE self, VALUE expval, VALUE cval, VALUE cspval)
9457 Double exponent, contraction, contraction_sp;
9458 Data_Get_Struct(self, Molecule, mol);
9459 exponent = NUM2DBL(rb_Float(expval));
9460 contraction = NUM2DBL(rb_Float(cval));
9461 contraction_sp = NUM2DBL(rb_Float(cspval));
9462 n = MoleculeAddGaussianPrimitiveCoefficients(mol, exponent, contraction, contraction_sp);
9464 rb_raise(rb_eMolbyError, "Molecule is emptry");
9466 rb_raise(rb_eMolbyError, "Low memory");
9468 rb_raise(rb_eMolbyError, "Unknown error");
9476 * Returns either "RHF", "UHF", or "ROHF". If no MO info is present, returns nil.
9479 s_Molecule_MOType(VALUE self)
9482 Data_Get_Struct(self, Molecule, mol);
9483 if (mol != NULL && mol->bset != NULL) {
9485 int rflag = mol->bset->rflag;
9488 else if (rflag == 2)
9491 return rb_str_new2(s);
9497 * set_mo_coefficients(idx, energy, coefficients)
9499 * To be used internally. Add a MO coefficients. Idx is the MO index (for open shell system,
9500 * beta MOs comes after all alpha MOs), energy is the MO energy, coefficients is an array
9501 * of MO coefficients.
9504 s_Molecule_SetMOCoefficients(VALUE self, VALUE ival, VALUE eval, VALUE aval)
9510 Data_Get_Struct(self, Molecule, mol);
9511 idx = NUM2INT(rb_Integer(ival));
9512 energy = NUM2DBL(rb_Float(eval));
9513 aval = rb_ary_to_ary(aval);
9514 ncomps = RARRAY_LEN(aval);
9515 coeffs = (Double *)calloc(sizeof(Double), ncomps);
9516 if (coeffs == NULL) {
9520 for (i = 0; i < ncomps; i++)
9521 coeffs[i] = NUM2DBL(rb_Float(RARRAY_PTR(aval)[i]));
9522 i = MoleculeSetMOCoefficients(mol, idx, energy, ncomps, coeffs);
9525 rb_raise(rb_eMolbyError, "Molecule is emptry");
9527 rb_raise(rb_eMolbyError, "Low memory");
9529 rb_raise(rb_eMolbyError, "Bad or inconsistent number of MOs");
9531 rb_raise(rb_eMolbyError, "Bad MO index");
9533 rb_raise(rb_eMolbyError, "Insufficient number of coefficients are given");
9535 rb_raise(rb_eMolbyError, "Unknown error");
9541 * allocate_basis_set_record(rflag, ne_alpha, ne_beta)
9543 * To be used internally. Allocate a basis set record. rflag: 0, unrestricted; 1, restricted.
9544 * ne_alpha, ne_beta: number of alpha/beta electrons.
9547 s_Molecule_AllocateBasisSetRecord(VALUE self, VALUE rval, VALUE naval, VALUE nbval)
9550 Int rflag, na, nb, n;
9551 Data_Get_Struct(self, Molecule, mol);
9552 rflag = NUM2INT(rb_Integer(rval));
9553 na = NUM2INT(rb_Integer(naval));
9554 nb = NUM2INT(rb_Integer(nbval));
9555 n = MoleculeAllocateBasisSetRecord(mol, rflag, na, nb);
9557 rb_raise(rb_eMolbyError, "Molecule is emptry");
9559 rb_raise(rb_eMolbyError, "Low memory");
9561 rb_raise(rb_eMolbyError, "Unknown error");
9567 * search_equivalent_atoms(ig = nil)
9569 * Search equivalent atoms (within the atom group if given). Returns an array of integers.
9572 s_Molecule_SearchEquivalentAtoms(int argc, VALUE *argv, VALUE self)
9578 Data_Get_Struct(self, Molecule, mol);
9579 if (mol->natoms == 0)
9581 rb_scan_args(argc, argv, "01", &val);
9583 ig = IntGroupFromValue(val);
9585 result = MoleculeSearchEquivalentAtoms(mol, ig);
9587 rb_raise(rb_eMolbyError, "Failed to search equivalent atoms (out of memory?)");
9589 IntGroupRelease(ig);
9590 val = rb_ary_new2(mol->natoms);
9591 for (i = 0; i < mol->natoms; i++)
9592 rb_ary_push(val, INT2NUM(result[i]));
9599 * create_pi_anchor(name, group [, type] [, weights] [, index]) -> AtomRef
9601 * Create a pi anchor, which is a "dummy" atom to represent pi-metal bonds.
9602 * Name is the name of the new pi anchor, and group is the atoms that define
9603 * the pi system. Type (a String) is an atom type for MM implementation.
9604 * Weights is the relative weights of the component atoms; if omitted, then
9605 * 1.0/n (n is the number of component atoms) is assumed for all atoms.
9606 * The weight values will be normalized so that the sum of the weights is 1.0.
9607 * The weight values must be positive.
9608 * Index is the atom index where the created pi-anchor is inserted in the
9609 * atoms array; if omitted, the pi-anchor is inserted after the component atom
9610 * having the largest index.
9613 s_Molecule_CreatePiAnchor(int argc, VALUE *argv, VALUE self)
9618 Int i, n, idx, last_component;
9622 if (argc < 2 || argc >= 6)
9623 rb_raise(rb_eMolbyError, "too %s arguments (should be 2..5)", (argc < 2 ? "few" : "many"));
9627 Data_Get_Struct(self, Molecule, mol);
9628 ig = IntGroupFromValue(gval);
9629 memset(&a, 0, sizeof(a));
9630 memset(&an, 0, sizeof(an));
9631 strncpy(a.aname, StringValuePtr(nval), 4);
9632 if (a.aname[0] == '_')
9633 rb_raise(rb_eMolbyError, "please avoid a name beginning with '_' for a pi anchor, because it causes some internal confusion.");
9634 a.type = AtomTypeEncodeToUInt("##"); /* Default atom type for pi_anchor */
9635 for (i = 0; (n = IntGroupGetNthPoint(ig, i)) >= 0; i++) {
9636 if (n >= mol->natoms) {
9637 AtomConnectResize(&an.connect, 0);
9638 rb_raise(rb_eMolbyError, "atom index (%d) out of range", n);
9640 AtomConnectInsertEntry(&an.connect, an.connect.count, n);
9643 if (an.connect.count == 0)
9644 rb_raise(rb_eMolbyError, "no atoms are specified");
9645 NewArray(&an.coeffs, &an.ncoeffs, sizeof(Double), an.connect.count);
9646 for (i = 0; i < an.connect.count; i++) {
9647 an.coeffs[i] = 1.0 / an.connect.count;
9649 if (argc > 0 && (argv[0] == Qnil || rb_obj_is_kind_of(argv[0], rb_cString))) {
9651 if (argv[0] != Qnil)
9652 a.type = AtomTypeEncodeToUInt(StringValuePtr(argv[0]));
9656 if (argc > 0 && (argv[0] == Qnil || rb_obj_is_kind_of(argv[0], rb_mEnumerable))) {
9657 if (argv[0] != Qnil) {
9658 VALUE aval = rb_ary_to_ary(argv[0]);
9660 if (RARRAY_LEN(aval) != an.connect.count)
9661 rb_raise(rb_eMolbyError, "the number of weight values does not match the number of atoms");
9662 for (i = 0, sum = 0.0; i < an.connect.count; i++) {
9663 d = NUM2DBL(rb_Float(RARRAY_PTR(aval)[i]));
9665 rb_raise(rb_eMolbyError, "the weight value must be positive");
9669 for (i = 0; i < an.connect.count; i++)
9670 an.coeffs[i] /= sum;
9675 if (argc > 0 && argv[0] != Qnil) {
9677 idx = NUM2INT(rb_Integer(argv[0]));
9679 if (idx < 0 || idx > mol->natoms) {
9680 /* Immediately after the last specified atom */
9681 idx = last_component + 1;
9683 a.anchor = (PiAnchor *)malloc(sizeof(PiAnchor));
9684 memmove(a.anchor, &an, sizeof(PiAnchor));
9685 /* Use residue information of the last specified atom */
9686 ap = ATOM_AT_INDEX(mol->atoms, last_component);
9687 a.resSeq = ap->resSeq;
9688 strncpy(a.resName, ap->resName, 4);
9689 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &a, idx, &idx) != 0)
9691 MoleculeCalculatePiAnchorPosition(mol, idx);
9692 aref = AtomRefNew(mol, idx);
9693 return Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
9698 * current -> Molecule
9700 * Get the currently "active" molecule.
9703 s_Molecule_Current(VALUE klass)
9705 return ValueFromMolecule(MoleculeCallback_currentMolecule());
9710 * Molecule[] -> Molecule
9711 * Molecule[n] -> Molecule
9712 * Molecule[name] -> Molecule
9713 * Molecule[name, k] -> Molecule
9714 * Molecule[regex] -> Molecule
9715 * Molecule[regex, k] -> Molecule
9717 * Molecule[] is equivalent to Molecule.current.
9718 * Molecule[n] (n is an integer) is equivalent to Molecule.list[n].
9719 * Molecule[name] gives the first document (in the order of creation time) that has
9720 * the given name. If a second argument (k) is given, the k-th document that has the
9721 * given name is returned.
9722 * Molecule[regex] gives the first document (in the order of creation time) that
9723 * has a name matching the regular expression. If a second argument (k) is given,
9724 * the k-th document that has a name matching the re is returned.
9727 s_Molecule_MoleculeAtIndex(int argc, VALUE *argv, VALUE klass)
9733 rb_scan_args(argc, argv, "02", &val, &kval);
9735 return s_Molecule_Current(klass);
9736 if (rb_obj_is_kind_of(val, rb_cInteger)) {
9738 mol = MoleculeCallback_moleculeAtIndex(idx);
9739 } else if (rb_obj_is_kind_of(val, rb_cString)) {
9740 char *p = StringValuePtr(val);
9741 k = (kval == Qnil ? 1 : NUM2INT(rb_Integer(kval)));
9742 for (idx = 0; (mol = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
9743 MoleculeCallback_displayName(mol, buf, sizeof buf);
9744 if (strcmp(buf, p) == 0 && --k == 0)
9747 } else if (rb_obj_is_kind_of(val, rb_cRegexp)) {
9748 k = (kval == Qnil ? 1 : NUM2INT(rb_Integer(kval)));
9749 for (idx = 0; (mol = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
9751 MoleculeCallback_displayName(mol, buf, sizeof buf);
9752 name = rb_str_new2(buf);
9753 if (rb_reg_match(val, name) != Qnil && --k == 0)
9756 } else rb_raise(rb_eTypeError, "the argument should be either empty, an integer, a string, or a regular expression");
9760 else return ValueFromMolecule(mol);
9765 * list -> array of Molecules
9767 * Get the list of molecules associated to the documents, in the order of creation
9768 * time of the document. If no document is open, returns an empry array.
9771 s_Molecule_List(VALUE klass)
9778 while ((mol = MoleculeCallback_moleculeAtIndex(i)) != NULL) {
9779 rb_ary_push(ary, ValueFromMolecule(mol));
9787 * ordered_list -> array of Molecules
9789 * Get the list of molecules associated to the documents, in the order of front-to-back
9790 * ordering of the associated window. If no document is open, returns an empry array.
9793 s_Molecule_OrderedList(VALUE klass)
9800 while ((mol = MoleculeCallback_moleculeAtOrderedIndex(i)) != NULL) {
9801 rb_ary_push(ary, ValueFromMolecule(mol));
9809 * error_message -> String
9811 * Get the error_message from the last load/save method. If no error, returns nil.
9814 s_Molecule_ErrorMessage(VALUE klass)
9816 if (gLoadSaveErrorMessage == NULL)
9818 else return rb_str_new2(gLoadSaveErrorMessage);
9823 * set_error_message(String)
9824 * Molecule.error_message = String
9826 * Get the error_message from the last load/save method. If no error, returns nil.
9829 s_Molecule_SetErrorMessage(VALUE klass, VALUE sval)
9831 if (gLoadSaveErrorMessage != NULL) {
9832 free(gLoadSaveErrorMessage);
9833 gLoadSaveErrorMessage = NULL;
9836 sval = rb_str_to_str(sval);
9837 gLoadSaveErrorMessage = strdup(StringValuePtr(sval));
9844 * self == Molecule -> boolean
9846 * True if the two arguments point to the same molecule.
9849 s_Molecule_Equal(VALUE self, VALUE val)
9851 if (rb_obj_is_kind_of(val, rb_cMolecule)) {
9852 Molecule *mol1, *mol2;
9853 Data_Get_Struct(self, Molecule, mol1);
9854 Data_Get_Struct(val, Molecule, mol2);
9855 return (mol1 == mol2 ? Qtrue : Qfalse);
9856 } else return Qfalse;
9864 /* Define module Molby */
9865 rb_mMolby = rb_define_module("Molby");
9867 /* Define Vector3D, Transform, IntGroup */
9870 /* Define MDArena */
9871 Init_MolbyMDTypes();
9873 /* class Molecule */
9874 rb_cMolecule = rb_define_class_under(rb_mMolby, "Molecule", rb_cObject);
9875 rb_define_alloc_func(rb_cMolecule, s_Molecule_Alloc);
9876 rb_define_private_method(rb_cMolecule, "initialize", s_Molecule_Initialize, -1);
9877 rb_define_private_method(rb_cMolecule, "initialize_copy", s_Molecule_InitCopy, 1);
9878 rb_define_method(rb_cMolecule, "loadmbsf", s_Molecule_Loadmbsf, -1);
9879 rb_define_method(rb_cMolecule, "loadpsf", s_Molecule_Loadpsf, -1);
9880 rb_define_alias(rb_cMolecule, "loadpsfx", "loadpsf");
9881 rb_define_method(rb_cMolecule, "loadpdb", s_Molecule_Loadpdb, -1);
9882 rb_define_method(rb_cMolecule, "loaddcd", s_Molecule_Loaddcd, -1);
9883 rb_define_method(rb_cMolecule, "loadtep", s_Molecule_Loadtep, -1);
9884 rb_define_method(rb_cMolecule, "loadres", s_Molecule_Loadres, -1);
9885 rb_define_method(rb_cMolecule, "loadfchk", s_Molecule_Loadfchk, -1);
9886 rb_define_alias(rb_cMolecule, "loadfch", "loadfchk");
9887 rb_define_method(rb_cMolecule, "loaddat", s_Molecule_Loaddat, -1);
9888 rb_define_method(rb_cMolecule, "molload", s_Molecule_Load, -1);
9889 rb_define_method(rb_cMolecule, "molsave", s_Molecule_Save, -1);
9890 rb_define_method(rb_cMolecule, "savembsf", s_Molecule_Savembsf, 1);
9891 rb_define_method(rb_cMolecule, "savepsf", s_Molecule_Savepsf, 1);
9892 rb_define_alias(rb_cMolecule, "savepsfx", "savepsf");
9893 rb_define_method(rb_cMolecule, "savepdb", s_Molecule_Savepdb, 1);
9894 rb_define_method(rb_cMolecule, "savedcd", s_Molecule_Savedcd, 1);
9895 /* rb_define_method(rb_cMolecule, "savetep", s_Molecule_Savetep, 1); */
9896 rb_define_method(rb_cMolecule, "name", s_Molecule_Name, 0);
9897 rb_define_method(rb_cMolecule, "set_name", s_Molecule_SetName, 1);
9898 rb_define_method(rb_cMolecule, "path", s_Molecule_Path, 0);
9899 rb_define_method(rb_cMolecule, "dir", s_Molecule_Dir, 0);
9900 rb_define_method(rb_cMolecule, "inspect", s_Molecule_Inspect, 0);
9901 rb_define_method(rb_cMolecule, "atoms", s_Molecule_Atoms, 0);
9902 rb_define_method(rb_cMolecule, "bonds", s_Molecule_Bonds, 0);
9903 rb_define_method(rb_cMolecule, "angles", s_Molecule_Angles, 0);
9904 rb_define_method(rb_cMolecule, "dihedrals", s_Molecule_Dihedrals, 0);
9905 rb_define_method(rb_cMolecule, "impropers", s_Molecule_Impropers, 0);
9906 rb_define_method(rb_cMolecule, "residues", s_Molecule_Residues, 0);
9907 rb_define_method(rb_cMolecule, "natoms", s_Molecule_Natoms, 0);
9908 rb_define_method(rb_cMolecule, "nbonds", s_Molecule_Nbonds, 0);
9909 rb_define_method(rb_cMolecule, "nangles", s_Molecule_Nangles, 0);
9910 rb_define_method(rb_cMolecule, "ndihedrals", s_Molecule_Ndihedrals, 0);
9911 rb_define_method(rb_cMolecule, "nimpropers", s_Molecule_Nimpropers, 0);
9913 rb_define_method(rb_cMolecule, "bond_par", s_Molecule_BondParIsObsolete, 1);
9914 rb_define_method(rb_cMolecule, "angle_par", s_Molecule_BondParIsObsolete, 1);
9915 rb_define_method(rb_cMolecule, "dihedral_par", s_Molecule_BondParIsObsolete, 1);
9916 rb_define_method(rb_cMolecule, "improper_par", s_Molecule_BondParIsObsolete, 1);
9917 rb_define_method(rb_cMolecule, "vdw_par", s_Molecule_BondParIsObsolete, 1);
9919 rb_define_method(rb_cMolecule, "start_step", s_Molecule_StartStep, 0);
9920 rb_define_method(rb_cMolecule, "start_step=", s_Molecule_SetStartStep, 1);
9921 rb_define_method(rb_cMolecule, "steps_per_frame", s_Molecule_StepsPerFrame, 0);
9922 rb_define_method(rb_cMolecule, "steps_per_frame=", s_Molecule_SetStepsPerFrame, 1);
9923 rb_define_method(rb_cMolecule, "ps_per_step", s_Molecule_PsPerStep, 0);
9924 rb_define_method(rb_cMolecule, "ps_per_step=", s_Molecule_SetPsPerStep, 1);
9926 rb_define_method(rb_cMolecule, "nresidues", s_Molecule_Nresidues, 0);
9927 rb_define_method(rb_cMolecule, "nresidues=", s_Molecule_ChangeNresidues, 1);
9928 rb_define_method(rb_cMolecule, "max_residue_number", s_Molecule_MaxResSeq, -1);
9929 rb_define_method(rb_cMolecule, "min_residue_number", s_Molecule_MinResSeq, -1);
9930 rb_define_method(rb_cMolecule, "each_atom", s_Molecule_EachAtom, -1);
9931 rb_define_method(rb_cMolecule, "cell", s_Molecule_Cell, 0);
9932 rb_define_method(rb_cMolecule, "cell=", s_Molecule_SetCell, -1);
9933 rb_define_alias(rb_cMolecule, "set_cell", "cell=");
9934 rb_define_method(rb_cMolecule, "box", s_Molecule_Box, 0);
9935 rb_define_method(rb_cMolecule, "box=", s_Molecule_SetBox, 1);
9936 rb_define_method(rb_cMolecule, "set_box", s_Molecule_SetBox, -2);
9937 rb_define_method(rb_cMolecule, "cell_transform", s_Molecule_CellTransform, 0);
9938 rb_define_method(rb_cMolecule, "cell_periodicity", s_Molecule_CellPeriodicity, 0);
9939 rb_define_method(rb_cMolecule, "cell_periodicity=", s_Molecule_SetCellPeriodicity, 1);
9940 rb_define_alias(rb_cMolecule, "set_cell_periodicity", "cell_periodicity=");
9941 rb_define_method(rb_cMolecule, "cell_flexibility", s_Molecule_CellFlexibility, 0);
9942 rb_define_method(rb_cMolecule, "cell_flexibility=", s_Molecule_SetCellFlexibility, 1);
9943 rb_define_alias(rb_cMolecule, "set_cell_flexibility", "cell_flexibility=");
9944 rb_define_method(rb_cMolecule, "symmetry", s_Molecule_Symmetry, 0);
9945 rb_define_alias(rb_cMolecule, "symmetries", "symmetry");
9946 rb_define_method(rb_cMolecule, "nsymmetries", s_Molecule_Nsymmetries, 0);
9947 rb_define_method(rb_cMolecule, "add_symmetry", s_Molecule_AddSymmetry, 1);
9948 rb_define_method(rb_cMolecule, "remove_symmetry", s_Molecule_RemoveSymmetry, -1);
9949 rb_define_alias(rb_cMolecule, "remove_symmetries", "remove_symmetry");
9950 rb_define_method(rb_cMolecule, "extract", s_Molecule_Extract, -1);
9951 rb_define_method(rb_cMolecule, "add", s_Molecule_Add, 1);
9952 rb_define_alias(rb_cMolecule, "+", "add");
9953 rb_define_method(rb_cMolecule, "remove", s_Molecule_Remove, 1);
9954 rb_define_method(rb_cMolecule, "atom_group", s_Molecule_AtomGroup, -1);
9955 rb_define_method(rb_cMolecule, "atom_index", s_Molecule_AtomIndex, 1);
9956 rb_define_method(rb_cMolecule, "create_atom", s_Molecule_CreateAnAtom, -1);
9957 rb_define_method(rb_cMolecule, "duplicate_atom", s_Molecule_DuplicateAnAtom, -1);
9958 rb_define_method(rb_cMolecule, "create_bond", s_Molecule_CreateBond, -1);
9959 rb_define_alias(rb_cMolecule, "create_bonds", "create_bond");
9960 rb_define_method(rb_cMolecule, "remove_bond", s_Molecule_RemoveBond, -1);
9961 rb_define_alias(rb_cMolecule, "remove_bonds", "remove_bond");
9962 rb_define_method(rb_cMolecule, "add_angle", s_Molecule_AddAngle, 3);
9963 rb_define_method(rb_cMolecule, "remove_angle", s_Molecule_RemoveAngle, 3);
9964 rb_define_method(rb_cMolecule, "add_dihedral", s_Molecule_AddDihedral, 4);
9965 rb_define_method(rb_cMolecule, "remove_dihedral", s_Molecule_RemoveDihedral, 4);
9966 rb_define_method(rb_cMolecule, "add_improper", s_Molecule_AddImproper, 4);
9967 rb_define_method(rb_cMolecule, "remove_improper", s_Molecule_RemoveImproper, 4);
9968 rb_define_method(rb_cMolecule, "assign_residue", s_Molecule_AssignResidue, 2);
9969 rb_define_method(rb_cMolecule, "offset_residue", s_Molecule_OffsetResidue, 2);
9970 rb_define_method(rb_cMolecule, "renumber_atoms", s_Molecule_RenumberAtoms, 1);
9971 rb_define_method(rb_cMolecule, "find_close_atoms", s_Molecule_FindCloseAtoms, -1);
9972 rb_define_method(rb_cMolecule, "guess_bonds", s_Molecule_GuessBonds, -1);
9973 rb_define_method(rb_cMolecule, "selection", s_Molecule_Selection, 0);
9974 rb_define_method(rb_cMolecule, "selection=", s_Molecule_SetSelection, 1);
9975 rb_define_method(rb_cMolecule, "set_undoable_selection", s_Molecule_SetUndoableSelection, 1);
9976 rb_define_method(rb_cMolecule, "hidden_atoms", s_Molecule_HiddenAtoms, 0); /* obsolete */
9977 rb_define_method(rb_cMolecule, "hidden_atoms=", s_Molecule_SetHiddenAtoms, 1); /* obsolete */
9978 rb_define_alias(rb_cMolecule, "set_hidden_atoms", "hidden_atoms="); /* obsolete */
9979 rb_define_method(rb_cMolecule, "frame", s_Molecule_Frame, 0);
9980 rb_define_method(rb_cMolecule, "frame=", s_Molecule_SelectFrame, 1);
9981 rb_define_alias(rb_cMolecule, "select_frame", "frame=");
9982 rb_define_method(rb_cMolecule, "nframes", s_Molecule_Nframes, 0);
9983 rb_define_method(rb_cMolecule, "create_frame", s_Molecule_CreateFrames, -1);
9984 rb_define_method(rb_cMolecule, "insert_frame", s_Molecule_InsertFrames, -1);
9985 rb_define_method(rb_cMolecule, "remove_frame", s_Molecule_RemoveFrames, -1);
9986 rb_define_alias(rb_cMolecule, "create_frames", "create_frame");
9987 rb_define_alias(rb_cMolecule, "insert_frames", "insert_frame");
9988 rb_define_alias(rb_cMolecule, "remove_frames", "remove_frame");
9989 rb_define_method(rb_cMolecule, "each_frame", s_Molecule_EachFrame, 0);
9990 rb_define_method(rb_cMolecule, "get_coord_from_frame", s_Molecule_GetCoordFromFrame, -1);
9991 rb_define_method(rb_cMolecule, "register_undo", s_Molecule_RegisterUndo, -1);
9992 rb_define_method(rb_cMolecule, "undo_enabled?", s_Molecule_UndoEnabled, 0);
9993 rb_define_method(rb_cMolecule, "undo_enabled=", s_Molecule_SetUndoEnabled, 1);
9994 rb_define_method(rb_cMolecule, "set_atom_attr", s_Molecule_SetAtomAttr, 3);
9995 rb_define_method(rb_cMolecule, "get_atom_attr", s_Molecule_GetAtomAttr, 2);
9996 rb_define_method(rb_cMolecule, "fragment", s_Molecule_Fragment, -1);
9997 rb_define_method(rb_cMolecule, "each_fragment", s_Molecule_EachFragment, 0);
9998 rb_define_method(rb_cMolecule, "detachable?", s_Molecule_Detachable_P, 1);
9999 rb_define_method(rb_cMolecule, "bonds_on_border", s_Molecule_BondsOnBorder, -1);
10000 rb_define_method(rb_cMolecule, "translate", s_Molecule_Translate, -1);
10001 rb_define_method(rb_cMolecule, "rotate", s_Molecule_Rotate, -1);
10002 rb_define_method(rb_cMolecule, "reflect", s_Molecule_Reflect, -1);
10003 rb_define_method(rb_cMolecule, "invert", s_Molecule_Invert, -1);
10004 rb_define_method(rb_cMolecule, "transform", s_Molecule_Transform, -1);
10005 rb_define_method(rb_cMolecule, "center_of_mass", s_Molecule_CenterOfMass, -1);
10006 rb_define_method(rb_cMolecule, "centralize", s_Molecule_Centralize, -1);
10007 rb_define_method(rb_cMolecule, "bounds", s_Molecule_Bounds, -1);
10008 rb_define_method(rb_cMolecule, "measure_bond", s_Molecule_MeasureBond, 2);
10009 rb_define_method(rb_cMolecule, "measure_angle", s_Molecule_MeasureAngle, 3);
10010 rb_define_method(rb_cMolecule, "measure_dihedral", s_Molecule_MeasureDihedral, 4);
10011 rb_define_method(rb_cMolecule, "expand_by_symmetry", s_Molecule_ExpandBySymmetry, -1);
10012 rb_define_method(rb_cMolecule, "amend_by_symmetry", s_Molecule_AmendBySymmetry, -1);
10013 rb_define_method(rb_cMolecule, "transform_for_symop", s_Molecule_TransformForSymop, -1);
10014 rb_define_method(rb_cMolecule, "symop_for_transform", s_Molecule_SymopForTransform, -1);
10015 rb_define_method(rb_cMolecule, "wrap_unit_cell", s_Molecule_WrapUnitCell, 1);
10016 rb_define_method(rb_cMolecule, "find_conflicts", s_Molecule_FindConflicts, -1);
10017 rb_define_method(rb_cMolecule, "fit_coordinates", s_Molecule_FitCoordinates, -1);
10018 rb_define_method(rb_cMolecule, "display", s_Molecule_Display, 0);
10019 rb_define_method(rb_cMolecule, "make_front", s_Molecule_MakeFront, 0);
10020 rb_define_method(rb_cMolecule, "update_enabled?", s_Molecule_UpdateEnabled, 0);
10021 rb_define_method(rb_cMolecule, "update_enabled=", s_Molecule_SetUpdateEnabled, 1);
10022 rb_define_method(rb_cMolecule, "show_unitcell", s_Molecule_ShowUnitCell, -1);
10023 rb_define_method(rb_cMolecule, "show_hydrogens", s_Molecule_ShowHydrogens, -1);
10024 rb_define_method(rb_cMolecule, "show_hydrogens=", s_Molecule_ShowHydrogens, -1);
10025 rb_define_method(rb_cMolecule, "show_dummy_atoms", s_Molecule_ShowDummyAtoms, -1);
10026 rb_define_method(rb_cMolecule, "show_dummy_atoms=", s_Molecule_ShowDummyAtoms, -1);
10027 rb_define_method(rb_cMolecule, "show_expanded", s_Molecule_ShowExpanded, -1);
10028 rb_define_method(rb_cMolecule, "show_expanded=", s_Molecule_ShowExpanded, -1);
10029 rb_define_method(rb_cMolecule, "is_atom_visible", s_Molecule_IsAtomVisible, 1);
10030 rb_define_method(rb_cMolecule, "show_ellipsoids", s_Molecule_ShowEllipsoids, -1);
10031 rb_define_method(rb_cMolecule, "show_ellipsoids=", s_Molecule_ShowEllipsoids, -1);
10032 rb_define_method(rb_cMolecule, "show_graphite", s_Molecule_ShowGraphite, -1);
10033 rb_define_method(rb_cMolecule, "show_graphite=", s_Molecule_ShowGraphite, -1);
10034 rb_define_method(rb_cMolecule, "show_graphite?", s_Molecule_ShowGraphiteFlag, 0);
10035 rb_define_method(rb_cMolecule, "show_periodic_image", s_Molecule_ShowPeriodicImage, -1);
10036 rb_define_method(rb_cMolecule, "show_periodic_image=", s_Molecule_ShowPeriodicImage, -1);
10037 rb_define_method(rb_cMolecule, "show_periodic_image?", s_Molecule_ShowPeriodicImageFlag, 0);
10038 rb_define_alias(rb_cMolecule, "show_unitcell=", "show_unitcell");
10039 rb_define_alias(rb_cMolecule, "show_unit_cell", "show_unitcell");
10040 rb_define_alias(rb_cMolecule, "show_unit_cell=", "show_unitcell");
10041 rb_define_alias(rb_cMolecule, "show_hydrogens=", "show_hydrogens");
10042 rb_define_alias(rb_cMolecule, "show_dummy_atoms=", "show_dummy_atoms");
10043 rb_define_alias(rb_cMolecule, "show_expanded=", "show_expanded");
10044 rb_define_alias(rb_cMolecule, "show_ellipsoids=", "show_ellipsoids");
10045 rb_define_alias(rb_cMolecule, "show_graphite=", "show_graphite");
10046 rb_define_alias(rb_cMolecule, "show_periodic_image=", "show_periodic_image");
10047 rb_define_method(rb_cMolecule, "line_mode", s_Molecule_LineMode, -1);
10048 rb_define_alias(rb_cMolecule, "line_mode=", "line_mode");
10049 rb_define_method(rb_cMolecule, "resize_to_fit", s_Molecule_ResizeToFit, 0);
10050 #if 1 || !defined(__CMDMAC__)
10051 rb_define_method(rb_cMolecule, "get_view_rotation", s_Molecule_GetViewRotation, 0);
10052 rb_define_method(rb_cMolecule, "get_view_scale", s_Molecule_GetViewScale, 0);
10053 rb_define_method(rb_cMolecule, "get_view_center", s_Molecule_GetViewCenter, 0);
10054 rb_define_method(rb_cMolecule, "set_view_rotation", s_Molecule_SetViewRotation, 2);
10055 rb_define_method(rb_cMolecule, "set_view_scale", s_Molecule_SetViewScale, 1);
10056 rb_define_method(rb_cMolecule, "set_view_center", s_Molecule_SetViewCenter, 1);
10057 rb_define_method(rb_cMolecule, "set_background_color", s_Molecule_SetBackgroundColor, -1);
10058 rb_define_method(rb_cMolecule, "create_graphic", s_Molecule_CreateGraphic, -1);
10059 rb_define_method(rb_cMolecule, "remove_graphic", s_Molecule_RemoveGraphic, 1);
10060 rb_define_method(rb_cMolecule, "ngraphics", s_Molecule_NGraphics, 0);
10061 rb_define_method(rb_cMolecule, "set_graphic_point", s_Molecule_SetGraphicPoint, 3);
10062 rb_define_method(rb_cMolecule, "set_graphic_color", s_Molecule_SetGraphicColor, 2);
10063 rb_define_method(rb_cMolecule, "show_graphic", s_Molecule_ShowGraphic, 1);
10064 rb_define_method(rb_cMolecule, "hide_graphic", s_Molecule_HideGraphic, 1);
10066 rb_define_method(rb_cMolecule, "show_text", s_Molecule_ShowText, 1);
10067 rb_define_method(rb_cMolecule, "md_arena", s_Molecule_MDArena, 0);
10068 rb_define_method(rb_cMolecule, "set_parameter_attr", s_Molecule_SetParameterAttr, 5);
10069 rb_define_method(rb_cMolecule, "parameter", s_Molecule_Parameter, 0);
10070 rb_define_method(rb_cMolecule, "selected_MO", s_Molecule_SelectedMO, 0);
10071 rb_define_method(rb_cMolecule, "default_MO_grid", s_Molecule_GetDefaultMOGrid, -1);
10072 rb_define_method(rb_cMolecule, "cubegen", s_Molecule_Cubegen, -1);
10073 rb_define_method(rb_cMolecule, "nelpots", s_Molecule_NElpots, 0);
10074 rb_define_method(rb_cMolecule, "elpot", s_Molecule_Elpot, 1);
10075 rb_define_method(rb_cMolecule, "add_gaussian_orbital_shell", s_Molecule_AddGaussianOrbitalShell, 3);
10076 rb_define_method(rb_cMolecule, "add_gaussian_primitive_coefficients", s_Molecule_AddGaussianPrimitiveCoefficients, 3);
10077 rb_define_method(rb_cMolecule, "mo_type", s_Molecule_MOType, 0);
10078 rb_define_method(rb_cMolecule, "set_mo_coefficients", s_Molecule_SetMOCoefficients, 3);
10079 rb_define_method(rb_cMolecule, "allocate_basis_set_record", s_Molecule_AllocateBasisSetRecord, 3);
10080 rb_define_method(rb_cMolecule, "search_equivalent_atoms", s_Molecule_SearchEquivalentAtoms, -1);
10082 rb_define_method(rb_cMolecule, "create_pi_anchor", s_Molecule_CreatePiAnchor, -1);
10083 rb_define_method(rb_cMolecule, "==", s_Molecule_Equal, 1);
10085 rb_define_singleton_method(rb_cMolecule, "current", s_Molecule_Current, 0);
10086 rb_define_singleton_method(rb_cMolecule, "[]", s_Molecule_MoleculeAtIndex, -1);
10087 rb_define_singleton_method(rb_cMolecule, "open", s_Molecule_Open, -1);
10088 rb_define_singleton_method(rb_cMolecule, "list", s_Molecule_List, 0);
10089 rb_define_singleton_method(rb_cMolecule, "ordered_list", s_Molecule_OrderedList, 0);
10090 rb_define_singleton_method(rb_cMolecule, "error_message", s_Molecule_ErrorMessage, 0);
10091 rb_define_singleton_method(rb_cMolecule, "set_error_message", s_Molecule_SetErrorMessage, 1);
10092 rb_define_singleton_method(rb_cMolecule, "error_message=", s_Molecule_SetErrorMessage, 1);
10094 /* class MolEnumerable */
10095 rb_cMolEnumerable = rb_define_class_under(rb_mMolby, "MolEnumerable", rb_cObject);
10096 rb_include_module(rb_cMolEnumerable, rb_mEnumerable);
10097 rb_define_method(rb_cMolEnumerable, "[]", s_MolEnumerable_Aref, 1);
10098 rb_define_method(rb_cMolEnumerable, "length", s_MolEnumerable_Length, 0);
10099 rb_define_alias(rb_cMolEnumerable, "size", "length");
10100 rb_define_method(rb_cMolEnumerable, "each", s_MolEnumerable_Each, 0);
10101 rb_define_method(rb_cMolEnumerable, "==", s_MolEnumerable_Equal, 1);
10103 /* class AtomRef */
10104 rb_cAtomRef = rb_define_class_under(rb_mMolby, "AtomRef", rb_cObject);
10105 for (i = 0; s_AtomAttrDefTable[i].name != NULL; i++) {
10107 snprintf(buf, sizeof buf - 1, "%s", s_AtomAttrDefTable[i].name);
10108 rb_define_method(rb_cAtomRef, buf, s_AtomAttrDefTable[i].getter, 0);
10109 s_AtomAttrDefTable[i].id = rb_intern(buf);
10110 *(s_AtomAttrDefTable[i].symref) = ID2SYM(s_AtomAttrDefTable[i].id);
10112 rb_define_method(rb_cAtomRef, buf, s_AtomAttrDefTable[i].setter, 1);
10114 rb_define_method(rb_cAtomRef, "[]=", s_AtomRef_SetAttr, 2);
10115 rb_define_alias(rb_cAtomRef, "set_attr", "[]=");
10116 rb_define_method(rb_cAtomRef, "[]", s_AtomRef_GetAttr, 1);
10117 rb_define_alias(rb_cAtomRef, "get_attr", "[]");
10118 s_SetAtomAttrString = rb_str_new2("set_atom_attr");
10119 rb_global_variable(&s_SetAtomAttrString);
10120 rb_define_method(rb_cAtomRef, "molecule", s_AtomRef_GetMolecule, 0);
10121 rb_define_method(rb_cAtomRef, "==", s_AtomRef_Equal, 1);
10123 /* class Parameter */
10124 rb_cParameter = rb_define_class_under(rb_mMolby, "Parameter", rb_cObject);
10125 rb_define_method(rb_cParameter, "bond", s_Parameter_Bond, 1);
10126 rb_define_method(rb_cParameter, "angle", s_Parameter_Angle, 1);
10127 rb_define_method(rb_cParameter, "dihedral", s_Parameter_Dihedral, 1);
10128 rb_define_method(rb_cParameter, "improper", s_Parameter_Improper, 1);
10129 rb_define_method(rb_cParameter, "vdw", s_Parameter_Vdw, 1);
10130 rb_define_method(rb_cParameter, "vdw_pair", s_Parameter_VdwPair, 1);
10131 rb_define_method(rb_cParameter, "vdw_cutoff", s_Parameter_VdwCutoff, 1);
10132 rb_define_method(rb_cParameter, "element", s_Parameter_Element, 1);
10133 rb_define_method(rb_cParameter, "nbonds", s_Parameter_Nbonds, 0);
10134 rb_define_method(rb_cParameter, "nangles", s_Parameter_Nangles, 0);
10135 rb_define_method(rb_cParameter, "ndihedrals", s_Parameter_Ndihedrals, 0);
10136 rb_define_method(rb_cParameter, "nimpropers", s_Parameter_Nimpropers, 0);
10137 rb_define_method(rb_cParameter, "nvdws", s_Parameter_Nvdws, 0);
10138 rb_define_method(rb_cParameter, "nvdw_pairs", s_Parameter_NvdwPairs, 0);
10139 rb_define_method(rb_cParameter, "nvdw_cutoffs", s_Parameter_NvdwCutoffs, 0);
10140 rb_define_method(rb_cParameter, "nelements", s_Parameter_Nelements, 0);
10141 rb_define_method(rb_cParameter, "bonds", s_Parameter_Bonds, 0);
10142 rb_define_method(rb_cParameter, "angles", s_Parameter_Angles, 0);
10143 rb_define_method(rb_cParameter, "dihedrals", s_Parameter_Dihedrals, 0);
10144 rb_define_method(rb_cParameter, "impropers", s_Parameter_Impropers, 0);
10145 rb_define_method(rb_cParameter, "vdws", s_Parameter_Vdws, 0);
10146 rb_define_method(rb_cParameter, "vdw_pairs", s_Parameter_VdwPairs, 0);
10147 rb_define_method(rb_cParameter, "vdw_cutoffs", s_Parameter_VdwCutoffs, 0);
10148 rb_define_method(rb_cParameter, "elements", s_Parameter_Elements, 0);
10149 rb_define_method(rb_cParameter, "lookup", s_Parameter_LookUp, -1);
10150 rb_define_method(rb_cParameter, "==", s_Parameter_Equal, 1);
10151 rb_define_singleton_method(rb_cParameter, "builtin", s_Parameter_Builtin, 0);
10152 rb_define_singleton_method(rb_cParameter, "bond", s_Parameter_Bond, 1);
10153 rb_define_singleton_method(rb_cParameter, "angle", s_Parameter_Angle, 1);
10154 rb_define_singleton_method(rb_cParameter, "dihedral", s_Parameter_Dihedral, 1);
10155 rb_define_singleton_method(rb_cParameter, "improper", s_Parameter_Improper, 1);
10156 rb_define_singleton_method(rb_cParameter, "vdw", s_Parameter_Vdw, 1);
10157 rb_define_singleton_method(rb_cParameter, "vdw_pair", s_Parameter_VdwPair, 1);
10158 rb_define_singleton_method(rb_cParameter, "vdw_cutoff", s_Parameter_VdwCutoff, 1);
10159 rb_define_singleton_method(rb_cParameter, "element", s_Parameter_Element, 1);
10160 rb_define_singleton_method(rb_cParameter, "nbonds", s_Parameter_Nbonds, 0);
10161 rb_define_singleton_method(rb_cParameter, "nangles", s_Parameter_Nangles, 0);
10162 rb_define_singleton_method(rb_cParameter, "ndihedrals", s_Parameter_Ndihedrals, 0);
10163 rb_define_singleton_method(rb_cParameter, "nimpropers", s_Parameter_Nimpropers, 0);
10164 rb_define_singleton_method(rb_cParameter, "nvdws", s_Parameter_Nvdws, 0);
10165 rb_define_singleton_method(rb_cParameter, "nvdw_pairs", s_Parameter_NvdwPairs, 0);
10166 rb_define_singleton_method(rb_cParameter, "nvdw_cutoffs", s_Parameter_NvdwCutoffs, 0);
10167 rb_define_singleton_method(rb_cParameter, "nelements", s_Parameter_Nelements, 0);
10168 rb_define_singleton_method(rb_cParameter, "bonds", s_Parameter_Bonds, 0);
10169 rb_define_singleton_method(rb_cParameter, "angles", s_Parameter_Angles, 0);
10170 rb_define_singleton_method(rb_cParameter, "dihedrals", s_Parameter_Dihedrals, 0);
10171 rb_define_singleton_method(rb_cParameter, "impropers", s_Parameter_Impropers, 0);
10172 rb_define_singleton_method(rb_cParameter, "vdws", s_Parameter_Vdws, 0);
10173 rb_define_singleton_method(rb_cParameter, "vdw_pairs", s_Parameter_VdwPairs, 0);
10174 rb_define_singleton_method(rb_cParameter, "vdw_cutoffs", s_Parameter_VdwCutoffs, 0);
10175 rb_define_singleton_method(rb_cParameter, "elements", s_Parameter_Elements, 0);
10176 rb_define_singleton_method(rb_cParameter, "lookup", s_Parameter_LookUp, -1);
10177 rb_define_const(rb_cParameter, "Builtin", Data_Wrap_Struct(rb_cParameter, 0, NULL, NULL));
10179 /* class ParEnumerable */
10180 rb_cParEnumerable = rb_define_class_under(rb_mMolby, "ParEnumerable", rb_cObject);
10181 rb_include_module(rb_cParEnumerable, rb_mEnumerable);
10182 rb_define_method(rb_cParEnumerable, "par_type", s_ParEnumerable_ParType, 0);
10183 rb_define_method(rb_cParEnumerable, "[]", s_ParEnumerable_Aref, 1);
10184 rb_define_method(rb_cParEnumerable, "length", s_ParEnumerable_Length, 0);
10185 rb_define_method(rb_cParEnumerable, "each", s_ParEnumerable_Each, 0);
10186 rb_define_method(rb_cParEnumerable, "reverse_each", s_ParEnumerable_ReverseEach, 0);
10187 rb_define_method(rb_cParEnumerable, "insert", s_ParEnumerable_Insert, -1);
10188 rb_define_method(rb_cParEnumerable, "delete", s_ParEnumerable_Delete, 1);
10189 rb_define_method(rb_cParEnumerable, "lookup", s_ParEnumerable_LookUp, -1);
10190 rb_define_method(rb_cParEnumerable, "==", s_ParEnumerable_Equal, 1);
10192 /* class ParameterRef */
10193 rb_cParameterRef = rb_define_class_under(rb_mMolby, "ParameterRef", rb_cObject);
10194 for (i = 0; s_ParameterAttrDefTable[i].name != NULL; i++) {
10196 snprintf(buf, sizeof buf - 1, "%s", s_ParameterAttrDefTable[i].name);
10197 rb_define_method(rb_cParameterRef, buf, s_ParameterAttrDefTable[i].getter, 0);
10198 s_ParameterAttrDefTable[i].id = rb_intern(buf);
10199 if (s_ParameterAttrDefTable[i].symref != NULL)
10200 *(s_ParameterAttrDefTable[i].symref) = ID2SYM(s_ParameterAttrDefTable[i].id);
10201 if (s_ParameterAttrDefTable[i].setter != NULL) {
10203 rb_define_method(rb_cParameterRef, buf, s_ParameterAttrDefTable[i].setter, 1);
10206 rb_define_method(rb_cParameterRef, "[]=", s_ParameterRef_SetAttr, 2);
10207 rb_define_alias(rb_cParameterRef, "set_attr", "[]=");
10208 rb_define_method(rb_cParameterRef, "[]", s_ParameterRef_GetAttr, 1);
10209 rb_define_alias(rb_cParameterRef, "get_attr", "[]");
10210 rb_define_method(rb_cParameterRef, "to_hash", s_ParameterRef_ToHash, 0);
10211 rb_define_method(rb_cParameterRef, "to_s", s_ParameterRef_ToString, 0);
10212 rb_define_method(rb_cParameterRef, "keys", s_ParameterRef_Keys, 0);
10213 rb_define_method(rb_cParameterRef, "==", s_ParameterRef_Equal, 1);
10215 /* class MolbyError */
10216 rb_eMolbyError = rb_define_class_under(rb_mMolby, "MolbyError", rb_eStandardError);
10218 /* module Kernel */
10219 rb_define_method(rb_mKernel, "check_interrupt", s_Kernel_CheckInterrupt, 0);
10220 rb_define_method(rb_mKernel, "get_interrupt_flag", s_GetInterruptFlag, 0);
10221 rb_define_method(rb_mKernel, "set_interrupt_flag", s_SetInterruptFlag, 1);
10222 rb_define_method(rb_mKernel, "show_progress_panel", s_ShowProgressPanel, -1);
10223 rb_define_method(rb_mKernel, "hide_progress_panel", s_HideProgressPanel, 0);
10224 rb_define_method(rb_mKernel, "set_progress_value", s_SetProgressValue, 1);
10225 rb_define_method(rb_mKernel, "set_progress_message", s_SetProgressMessage, 1);
10226 rb_define_method(rb_mKernel, "ask", s_Kernel_Ask, -1);
10227 rb_define_method(rb_mKernel, "register_menu", s_Kernel_RegisterMenu, 2);
10228 rb_define_method(rb_mKernel, "lookup_menu", s_Kernel_LookupMenu, 1);
10229 rb_define_method(rb_mKernel, "get_global_settings", s_Kernel_GetGlobalSettings, 1);
10230 rb_define_method(rb_mKernel, "set_global_settings", s_Kernel_SetGlobalSettings, 2);
10231 rb_define_method(rb_mKernel, "execute_script", s_Kernel_ExecuteScript, 1);
10232 rb_define_method(rb_mKernel, "document_home", s_Kernel_DocumentHome, 0);
10233 rb_define_method(rb_mKernel, "call_subprocess", s_Kernel_CallSubProcess, 2);
10234 rb_define_method(rb_mKernel, "message_box", s_Kernel_MessageBox, -1);
10235 rb_define_method(rb_mKernel, "error_message_box", s_Kernel_ErrorMessageBox, 1);
10237 s_ID_equal = rb_intern("==");
10240 #pragma mark ====== External functions ======
10242 static VALUE s_ruby_top_self = Qfalse;
10245 s_evalRubyScriptOnMoleculeSub(VALUE val)
10247 void **ptr = (void **)val;
10248 Molecule *mol = (Molecule *)ptr[1];
10249 VALUE sval = rb_str_new2((char *)ptr[0]);
10251 if (s_ruby_top_self == Qfalse) {
10252 s_ruby_top_self = rb_eval_string("eval(\"self\",TOPLEVEL_BINDING)");
10254 if (ptr[2] == NULL) {
10257 fnval = Ruby_NewFileStringValue((char *)ptr[2]);
10261 return rb_funcall(s_ruby_top_self, rb_intern("eval"), 1, sval);
10263 return rb_funcall(s_ruby_top_self, rb_intern("eval"), 4, sval, Qnil, fnval, INT2FIX(1));
10265 VALUE mval = ValueFromMolecule(mol);
10267 return rb_funcall(mval, rb_intern("instance_eval"), 1, sval);
10268 else return rb_funcall(mval, rb_intern("instance_eval"), 3, sval, fnval, INT2FIX(1));
10273 Molby_evalRubyScriptOnMolecule(const char *script, Molecule *mol, const char *fname, int *status)
10277 VALUE save_interrupt_flag;
10278 char *save_ruby_sourcefile;
10279 int save_ruby_sourceline;
10280 if (gMolbyIsCheckingInterrupt) {
10281 MolActionAlertRubyIsRunning();
10283 return (RubyValue)Qnil;
10286 args[0] = (void *)script;
10287 args[1] = (void *)mol;
10288 args[2] = (void *)fname;
10289 save_interrupt_flag = s_SetInterruptFlag(Qnil, Qtrue);
10290 save_ruby_sourcefile = ruby_sourcefile;
10291 save_ruby_sourceline = ruby_sourceline;
10292 retval = (RubyValue)rb_protect(s_evalRubyScriptOnMoleculeSub, (VALUE)args, status);
10293 if (*status != 0) {
10294 /* Is this 'exit' exception? */
10295 VALUE last_exception = rb_gv_get("$!");
10296 if (rb_obj_is_kind_of(last_exception, rb_eSystemExit)) {
10297 /* Capture exit and return the status value */
10298 retval = (RubyValue)rb_funcall(last_exception, rb_intern("status"), 0);
10302 s_SetInterruptFlag(Qnil, save_interrupt_flag);
10303 ruby_sourcefile = save_ruby_sourcefile;
10304 ruby_sourceline = save_ruby_sourceline;
10310 Molby_showRubyValue(RubyValue value, char **outValueString)
10312 VALUE val = (VALUE)value;
10313 if (gMolbyIsCheckingInterrupt) {
10314 MolActionAlertRubyIsRunning();
10321 val = rb_protect(rb_inspect, val, &status);
10323 str = StringValuePtr(val);
10324 if (outValueString != NULL)
10325 *outValueString = strdup(str);
10326 MyAppCallback_showScriptMessage("%s", str);
10331 Molby_showError(int status)
10333 static const int tag_raise = 6;
10334 char *msg = NULL, *msg2;
10335 VALUE val, backtrace;
10336 int interrupted = 0;
10337 if (status == tag_raise) {
10338 VALUE eclass = CLASS_OF(ruby_errinfo);
10339 if (eclass == rb_eInterrupt) {
10345 backtrace = rb_eval_string_protect("$backtrace = $!.backtrace.join(\"\\n\")", &status);
10347 val = rb_eval_string_protect("$!.to_s", &status);
10349 msg = RSTRING_PTR(val);
10350 else msg = "(message not available)";
10352 asprintf(&msg2, "%s\n%s", msg, RSTRING_PTR(backtrace));
10353 MyAppCallback_messageBox(msg2, (interrupted == 0 ? "Molby script error" : "Molby script interrupted"), 0, 3);
10359 Molby_getDescription(void)
10361 extern const char *gVersionString, *gCopyrightString;
10362 extern int gRevisionNumber;
10363 extern char *gLastBuildString;
10365 char *revisionString;
10366 if (gRevisionNumber > 0) {
10367 asprintf(&revisionString, ", revision %d", gRevisionNumber);
10368 } else revisionString = "";
10370 "Molby %s%s\n%s\nLast compile: %s\n"
10371 #if !defined(__CMDMAC__)
10378 gVersionString, revisionString, gCopyrightString, gLastBuildString,
10379 #if !defined(__CMDMAC__)
10380 MyAppCallback_getGUIDescriptionString(),
10382 gRubyVersion, gRubyCopyright);
10383 if (revisionString[0] != 0)
10384 free(revisionString);
10389 Molby_startup(const char *script, const char *dir)
10394 char *respath, *p, *wbuf;
10396 /* Get version/copyright string from Ruby interpreter */
10398 gRubyVersion = strdup(ruby_version);
10399 asprintf(&gRubyCopyright, "%sCopyright (C) %d-%d %s",
10400 #if defined(__CMDMAC__)
10403 " ", /* Indent for displaying in About dialog */
10405 RUBY_BIRTH_YEAR, RUBY_RELEASE_YEAR, RUBY_AUTHOR);
10408 /* Read build and revision information for Molby */
10411 extern int gRevisionNumber;
10412 extern char *gLastBuildString;
10413 FILE *fp = fopen("../buildInfo.txt", "r");
10414 gLastBuildString = "";
10416 if (fgets(buf, sizeof(buf), fp) != NULL) {
10417 char *p1 = strchr(buf, '\"');
10418 char *p2 = strrchr(buf, '\"');
10419 if (p1 != NULL && p2 != NULL && p2 - p1 > 1) {
10420 memmove(buf, p1 + 1, p2 - p1 - 1);
10421 buf[p2 - p1 - 1] = 0;
10422 asprintf(&gLastBuildString, "Last compile: %s\n", buf);
10427 fp = fopen("../revisionInfo.txt", "r");
10428 gRevisionNumber = 0;
10430 if (fgets(buf, sizeof(buf), fp) != NULL) {
10431 gRevisionNumber = strtol(buf, NULL, 0);
10437 #if defined(__CMDMAC__)
10438 wbuf = Molby_getDescription();
10439 printf("%s\n", wbuf);
10443 /* Read atom display parameters */
10444 if (ElementParameterInitialize("element.par", &wbuf) != 0) {
10445 #if defined(__CMDMAC__)
10446 fprintf(stderr, "%s\n", wbuf);
10448 MyAppCallback_setConsoleColor(1);
10449 MyAppCallback_showScriptMessage("%s", wbuf);
10450 MyAppCallback_setConsoleColor(0);
10455 /* Read default parameters */
10456 ParameterReadFromFile(gBuiltinParameters, "default.par", &wbuf, NULL);
10457 if (wbuf != NULL) {
10458 #if defined(__CMDMAC__)
10459 fprintf(stderr, "%s\n", wbuf);
10461 MyAppCallback_setConsoleColor(1);
10462 MyAppCallback_showScriptMessage("%s", wbuf);
10463 MyAppCallback_setConsoleColor(0);
10468 /* Initialize Ruby interpreter */
10471 /* Initialize loadpath; the specified directory, "lib" subdirectory, and "." */
10473 asprintf(&libpath, "%s%clib", dir, PATH_SEPARATOR);
10474 ruby_incpush(libpath);
10478 ruby_script("Molby");
10480 /* Find the resource path (the parent directory of the given directory) */
10481 respath = strdup(dir);
10482 p = strrchr(respath, '/');
10483 if (p == NULL && PATH_SEPARATOR != '/')
10484 p = strrchr(respath, PATH_SEPARATOR);
10487 val = Ruby_NewFileStringValue(respath);
10488 rb_define_global_const("MolbyResourcePath", val);
10491 /* Define Molby classes */
10493 RubyDialogInitClass();
10495 rb_define_const(rb_mMolby, "ResourcePath", val);
10496 val = Ruby_NewFileStringValue(dir);
10497 rb_define_const(rb_mMolby, "ScriptPath", val);
10498 asprintf(&p, "%s%c%s", dir, PATH_SEPARATOR, "mbsf");
10499 val = Ruby_NewFileStringValue(p);
10500 rb_define_const(rb_mMolby, "MbsfPath", val);
10503 #if defined(__CMDMAC__)
10504 rb_define_const(rb_mMolby, "HasGUI", Qfalse);
10506 rb_define_const(rb_mMolby, "HasGUI", Qtrue);
10511 /* Create objects for stdout and stderr */
10512 val = rb_funcall(rb_cObject, rb_intern("new"), 0);
10513 rb_define_singleton_method(val, "write", s_StandardOutput, 1);
10514 rb_gv_set("$stdout", val);
10515 val = rb_funcall(rb_cObject, rb_intern("new"), 0);
10516 rb_define_singleton_method(val, "write", s_StandardErrorOutput, 1);
10517 rb_gv_set("$stderr", val);
10519 /* Create objects for stdin */
10520 val = rb_funcall(rb_cObject, rb_intern("new"), 0);
10521 rb_define_singleton_method(val, "gets", s_StandardInputGets, -1);
10522 rb_define_singleton_method(val, "readline", s_StandardInputGets, -1);
10523 rb_define_singleton_method(val, "method_missing", s_StandardInputMethodMissing, -1);
10524 rb_gv_set("$stdin", val);
10528 /* Global variable to hold backtrace */
10529 rb_define_variable("$backtrace", &gMolbyBacktrace);
10532 /* Register interrupt check code */
10533 rb_add_event_hook(s_Event_Callback, RUBY_EVENT_ALL);
10537 /* Start interval timer (for periodic polling of interrupt); firing every 50 msec */
10538 s_SetIntervalTimer(0, 50);
10541 /* Read the startup script */
10542 if (script != NULL && script[0] != 0) {
10543 MyAppCallback_showScriptMessage("Evaluating %s...\n", script);
10545 rb_load_protect(rb_str_new2(script), 0, &status);
10548 Molby_showError(status);
10550 MyAppCallback_showScriptMessage("Done.\n");
10555 Molby_buildARGV(int argc, const char **argv)
10558 rb_ary_clear(rb_argv);
10559 for (i = 0; i < argc; i++) {
10560 VALUE arg = rb_tainted_str_new2(argv[i]);
10562 rb_ary_push(rb_argv, arg);