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);
2094 #pragma mark ====== Parameter Class ======
2096 /* The Parameter class actually encapsulate Molecule record. If the record pointer
2097 * is NULL, then the global parameters are looked for. */
2099 /* Rebuild the MD parameter record if necessary: may throw an exception */
2100 /* The second parameter is passed to md_arena.prepare; if true, then check only */
2102 s_RebuildMDParameterIfNecessary(VALUE val, VALUE cval)
2105 Data_Get_Struct(val, Molecule, mol);
2107 rb_raise(rb_eMolbyError, "the molecule is empty");
2108 if (mol->par == NULL || mol->arena == NULL || mol->arena->is_initialized == 0 || mol->needsMDRebuild) {
2109 /* Do self.md_arena.prepare */
2110 VALUE val2 = rb_funcall(val, rb_intern("md_arena"), 0);
2112 val2 = rb_funcall(val2, rb_intern("prepare"), 1, cval);
2117 s_NewParameterValueFromValue(VALUE val)
2120 if (rb_obj_is_kind_of(val, rb_cMolecule)) {
2121 Data_Get_Struct(val, Molecule, mol);
2122 s_RebuildMDParameterIfNecessary(val, Qtrue);
2123 MoleculeRetain(mol);
2124 return Data_Wrap_Struct(rb_cParameter, 0, (void (*)(void *))MoleculeRelease, mol);
2127 return Data_Wrap_Struct(rb_cParameter, 0, NULL, mol);
2132 s_MoleculeFromParameterValue(VALUE val)
2135 Data_Get_Struct(val, Molecule, mol);
2140 s_ParameterFromParameterValue(VALUE val)
2143 Data_Get_Struct(val, Molecule, mol);
2146 return gBuiltinParameters;
2149 /* Forward declarations */
2150 static VALUE s_NewParEnumerableValueFromMoleculeAndType(Molecule *mol, Int parType);
2151 static Molecule *s_MoleculeFromParEnumerableValue(VALUE val);
2154 s_MoleculeFromParameterOrParEnumerableValue(VALUE val)
2156 if (val == rb_cParameter) {
2157 return NULL; /* Parameter class method: builtin parameters */
2158 } else if (rb_obj_is_kind_of(val, rb_cParameter)) {
2159 return s_MoleculeFromParameterValue(val);
2160 } else if (rb_obj_is_kind_of(val, rb_cParEnumerable)) {
2161 return s_MoleculeFromParEnumerableValue(val);
2167 * builtin -> Parameter
2169 * Returns a parameter value that points to the global (builtin) parameters.
2170 * Equivalent to Parameter::Builtin (constant).
2173 s_Parameter_Builtin(VALUE self)
2175 static ID s_builtin_id = 0;
2176 if (s_builtin_id == 0)
2177 s_builtin_id = rb_intern("Builtin");
2178 return rb_const_get(rb_cParameter, s_builtin_id);
2183 * bond(idx) -> ParameterRef
2185 * The index-th bond parameter record is returned.
2188 s_Parameter_Bond(VALUE self, VALUE ival)
2192 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2193 idx = NUM2INT(rb_Integer(ival));
2195 n = gBuiltinParameters->nbondPars;
2196 else if (mol->par != NULL)
2197 n = mol->par->nbondPars;
2199 if (idx < -n || idx >= n)
2200 rb_raise(rb_eMolbyError, "Bond parameter index (%d) out of range", idx);
2203 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kBondParType, idx);
2208 * angle(idx) -> ParameterRef
2210 * The index-th angle parameter record is returned.
2213 s_Parameter_Angle(VALUE self, VALUE ival)
2217 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2218 idx = NUM2INT(rb_Integer(ival));
2220 n = gBuiltinParameters->nanglePars;
2221 else if (mol->par != NULL)
2222 n = mol->par->nanglePars;
2224 if (idx < -n || idx >= n)
2225 rb_raise(rb_eMolbyError, "Angle parameter index (%d) out of range", idx);
2228 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kAngleParType, idx);
2233 * dihedral(idx) -> ParameterRef
2235 * The index-th dihedral parameter record is returned.
2238 s_Parameter_Dihedral(VALUE self, VALUE ival)
2242 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2243 idx = NUM2INT(rb_Integer(ival));
2245 n = gBuiltinParameters->ndihedralPars;
2246 else if (mol->par != NULL)
2247 n = mol->par->ndihedralPars;
2249 if (idx < -n || idx >= n)
2250 rb_raise(rb_eMolbyError, "Dihedral parameter index (%d) out of range", idx);
2253 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kDihedralParType, idx);
2258 * improper(idx) -> ParameterRef
2260 * The index-th improper parameter record is returned.
2263 s_Parameter_Improper(VALUE self, VALUE ival)
2267 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2268 idx = NUM2INT(rb_Integer(ival));
2270 n = gBuiltinParameters->nimproperPars;
2271 else if (mol->par != NULL)
2272 n = mol->par->nimproperPars;
2274 if (idx < -n || idx >= n)
2275 rb_raise(rb_eMolbyError, "Improper parameter index (%d) out of range", idx);
2278 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kImproperParType, idx);
2283 * vdw(idx) -> ParameterRef
2285 * The index-th vdw parameter record is returned.
2288 s_Parameter_Vdw(VALUE self, VALUE ival)
2292 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2293 idx = NUM2INT(rb_Integer(ival));
2295 n = gBuiltinParameters->nvdwPars;
2296 else if (mol->par != NULL)
2297 n = mol->par->nvdwPars;
2299 if (idx < -n || idx >= n)
2300 rb_raise(rb_eMolbyError, "Vdw parameter index (%d) out of range", idx);
2303 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwParType, idx);
2308 * vdw_pair(idx) -> ParameterRef
2310 * The index-th vdw pair parameter record is returned.
2313 s_Parameter_VdwPair(VALUE self, VALUE ival)
2317 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2318 idx = NUM2INT(rb_Integer(ival));
2320 n = gBuiltinParameters->nvdwpPars;
2321 else if (mol->par != NULL)
2322 n = mol->par->nvdwpPars;
2324 if (idx < -n || idx >= n)
2325 rb_raise(rb_eMolbyError, "Vdw pair parameter index (%d) out of range", idx);
2328 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwPairParType, idx);
2333 * vdw_cutoff(idx) -> ParameterRef
2335 * The index-th vdw cutoff parameter record is returned.
2338 s_Parameter_VdwCutoff(VALUE self, VALUE ival)
2342 mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2343 idx = NUM2INT(rb_Integer(ival));
2345 n = gBuiltinParameters->nvdwCutoffPars;
2346 else if (mol->par != NULL)
2347 n = mol->par->nvdwCutoffPars;
2349 if (idx < -n || idx >= n)
2350 rb_raise(rb_eMolbyError, "Dihedral parameter index (%d) out of range", idx);
2353 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwCutoffParType, idx);
2358 * element(idx) -> ParameterRef
2359 * element(t1) -> ParameterRef
2361 * In the first form, the index-th element parameter record is returned. In the second
2362 * form, the element parameter for t1 is looked up (the last index first). t1
2363 * is the element name string (up to 4 characters).
2364 * Unlike other Parameter methods, this is used only for the global parameter.
2367 s_Parameter_Element(VALUE self, VALUE ival)
2370 if (rb_obj_is_kind_of(ival, rb_cNumeric)) {
2371 int n = gCountElementParameters;
2372 idx1 = NUM2INT(rb_Integer(ival));
2373 if (idx1 < -n || idx1 >= n)
2374 rb_raise(rb_eMolbyError, "Element parameter index (%d) out of range", idx1);
2377 return ValueFromMoleculeWithParameterTypeAndIndex(NULL, kElementParType, idx1);
2382 strncpy(name, StringValuePtr(ival), 4);
2384 for (i = gCountElementParameters - 1, ep = gElementParameters + i; i >= 0; i--, ep--) {
2385 if (strncmp(ep->name, name, 4) == 0)
2386 return ValueFromMoleculeWithParameterTypeAndIndex(NULL, kElementParType, i);
2396 * Returns the number of bond parameters.
2399 s_Parameter_Nbonds(VALUE self)
2402 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2404 n = gBuiltinParameters->nbondPars;
2405 else if (mol->par != NULL)
2406 n = mol->par->nbondPars;
2413 * nangles -> Integer
2415 * Returns the number of angle parameters.
2418 s_Parameter_Nangles(VALUE self)
2421 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2423 n = gBuiltinParameters->nanglePars;
2424 else if (mol->par != NULL)
2425 n = mol->par->nanglePars;
2432 * ndihedrals -> Integer
2434 * Returns the number of dihedral parameters.
2437 s_Parameter_Ndihedrals(VALUE self)
2440 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2442 n = gBuiltinParameters->ndihedralPars;
2443 else if (mol->par != NULL)
2444 n = mol->par->ndihedralPars;
2451 * nimpropers -> Integer
2453 * Returns the number of improper parameters.
2456 s_Parameter_Nimpropers(VALUE self)
2459 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2461 n = gBuiltinParameters->nimproperPars;
2462 else if (mol->par != NULL)
2463 n = mol->par->nimproperPars;
2472 * Returns the number of vdw parameters.
2475 s_Parameter_Nvdws(VALUE self)
2478 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2480 n = gBuiltinParameters->nvdwPars;
2481 else if (mol->par != NULL)
2482 n = mol->par->nvdwPars;
2489 * nvdw_pairs -> Integer
2491 * Returns the number of vdw pair parameters.
2494 s_Parameter_NvdwPairs(VALUE self)
2497 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2499 n = gBuiltinParameters->nvdwpPars;
2500 else if (mol->par != NULL)
2501 n = mol->par->nvdwpPars;
2508 * nvdw_cutoffs -> Integer
2510 * Returns the number of vdw cutoff parameters.
2513 s_Parameter_NvdwCutoffs(VALUE self)
2516 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2518 n = gBuiltinParameters->nvdwCutoffPars;
2519 else if (mol->par != NULL)
2520 n = mol->par->nvdwCutoffPars;
2527 * nelements -> Integer
2529 * Returns the number of element parameters.
2532 s_Parameter_Nelements(VALUE self)
2534 return INT2NUM(gCountElementParameters);
2539 * bonds -> ParEnumerable
2541 * Returns a ParEnumerable value that (formally) points to the collection of bond parameters.
2542 * Parameter.bonds[x] is equivalent to Parameter.bond(x). ParEnumerable class is
2543 * useful when all accessible parameters should be examined by use of 'each' method.
2546 s_Parameter_Bonds(VALUE self)
2548 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2549 return s_NewParEnumerableValueFromMoleculeAndType(mol, kBondParType);
2554 * angles -> ParEnumerable
2556 * Returns a ParEnumerable value that (formally) points to the collection of angle parameters.
2557 * Parameter.angles[x] is equivalent to Parameter.angle(x). ParEnumerable class is
2558 * useful when all accessible parameters should be examined by use of 'each' method.
2561 s_Parameter_Angles(VALUE self)
2563 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2564 return s_NewParEnumerableValueFromMoleculeAndType(mol, kAngleParType);
2569 * dihedrals -> ParEnumerable
2571 * Returns a ParEnumerable value that (formally) points to the collection of dihedral parameters.
2572 * Parameter.dihedrals[x] is equivalent to Parameter.dihedral(x). ParEnumerable class is
2573 * useful when all accessible parameters should be examined by use of 'each' method.
2576 s_Parameter_Dihedrals(VALUE self)
2578 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2579 return s_NewParEnumerableValueFromMoleculeAndType(mol, kDihedralParType);
2584 * impropers -> ParEnumerable
2586 * Returns a ParEnumerable value that (formally) points to the collection of improper parameters.
2587 * Parameter.impropers[x] is equivalent to Parameter.improper(x). ParEnumerable class is
2588 * useful when all accessible parameters should be examined by use of 'each' method.
2591 s_Parameter_Impropers(VALUE self)
2593 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2594 return s_NewParEnumerableValueFromMoleculeAndType(mol, kImproperParType);
2599 * vdws -> ParEnumerable
2601 * Returns a ParEnumerable value that (formally) points to the collection of vdw parameters.
2602 * Parameter.vdws[x] is equivalent to Parameter.vdw(x). ParEnumerable class is
2603 * useful when all accessible parameters should be examined by use of 'each' method.
2606 s_Parameter_Vdws(VALUE self)
2608 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2609 return s_NewParEnumerableValueFromMoleculeAndType(mol, kVdwParType);
2614 * vdw_pairs -> ParEnumerable
2616 * Returns a ParEnumerable value that (formally) points to the collection of vdw pair parameters.
2617 * Parameter.vdw_pairs[x] is equivalent to Parameter.vdw_pair(x). ParEnumerable class is
2618 * useful when all accessible parameters should be examined by use of 'each' method.
2621 s_Parameter_VdwPairs(VALUE self)
2623 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2624 return s_NewParEnumerableValueFromMoleculeAndType(mol, kVdwPairParType);
2629 * vdw_cutoffs -> ParEnumerable
2631 * Returns a ParEnumerable value that (formally) points to the collection of vdw cutoff parameters.
2632 * Parameter.vdw_cutoffs[x] is equivalent to Parameter.vdw_cutoff(x). ParEnumerable class is
2633 * useful when all accessible parameters should be examined by use of 'each' method.
2636 s_Parameter_VdwCutoffs(VALUE self)
2638 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2639 return s_NewParEnumerableValueFromMoleculeAndType(mol, kVdwCutoffParType);
2644 * elements -> ParEnumerable
2646 * Returns a ParEnumerable value that (formally) points to the collection of element parameters.
2647 * Parameter.elements[x] is equivalent to Parameter.element(x). ParEnumerable class is
2648 * useful when all accessible parameters should be examined by use of 'each' method.
2651 s_Parameter_Elements(VALUE self)
2653 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2654 return s_NewParEnumerableValueFromMoleculeAndType(mol, kElementParType);
2658 s_Parameter_Lookup_sub(int argc, VALUE *argv, int parType, Molecule *mol)
2660 VALUE atval, optval;
2663 int i, n, idx, flags, is_global;
2665 rb_scan_args(argc, argv, "1*", &atval, &optval);
2667 /* Get the atom types */
2669 case kBondParType: n = 2; break;
2670 case kAngleParType: n = 3; break;
2671 case kDihedralParType: n = 4; break;
2672 case kImproperParType: n = 4; break;
2673 case kVdwParType: n = 1; break;
2674 case kVdwPairParType: n = 2; break;
2675 default: return Qnil;
2677 s_ScanAtomTypes(atval, n, t);
2678 for (i = 0; i < n; i++) {
2679 if (t[i] < kAtomTypeMinimum) {
2680 /* Explicit atom index */
2682 rb_raise(rb_eMolbyError, "Explicit atom index (%d) is invalid for global parameters", t[i]);
2683 if (t[i] >= mol->natoms)
2684 rb_raise(rb_eMolbyError, "Atom index (%d) out of range", t[i]);
2686 t[i] = ATOM_AT_INDEX(mol->atoms, t[i])->type;
2690 /* Analyze options */
2692 n = RARRAY_LEN(optval);
2693 for (i = 0; i < n; i++) {
2694 VALUE oval = RARRAY_PTR(optval)[i];
2695 if (oval == ID2SYM(rb_intern("global")))
2696 flags |= kParameterLookupGlobal;
2697 else if (oval == ID2SYM(rb_intern("local")))
2698 flags |= kParameterLookupLocal;
2699 else if (oval == ID2SYM(rb_intern("missing")))
2700 flags |= kParameterLookupMissing;
2701 else if (oval == ID2SYM(rb_intern("nowildcard")))
2702 flags |= kParameterLookupNoWildcard;
2703 else if (oval == ID2SYM(rb_intern("nobasetype")))
2704 flags |= kParameterLookupNoBaseAtomType;
2705 else if (oval == ID2SYM(rb_intern("create")))
2709 flags = kParameterLookupGlobal | kParameterLookupLocal;
2714 case kBondParType: {
2717 bp = ParameterLookupBondPar(mol->par, t[0], t[1], ii[0], ii[1], flags);
2719 idx = bp - mol->par->bondPars;
2723 bp = ParameterLookupBondPar(gBuiltinParameters, t[0], t[1], -1, -1, flags);
2725 idx = bp - gBuiltinParameters->bondPars;
2730 case kAngleParType: {
2733 ap = ParameterLookupAnglePar(mol->par, t[0], t[1], t[2], ii[0], ii[1], ii[2], flags);
2735 idx = ap - mol->par->anglePars;
2739 ap = ParameterLookupAnglePar(gBuiltinParameters, t[0], t[1], t[2], -1, -1, -1, flags);
2741 idx = ap - gBuiltinParameters->anglePars;
2746 case kDihedralParType: {
2749 tp = ParameterLookupDihedralPar(mol->par, t[0], t[1], t[2], t[3], ii[0], ii[1], ii[2], ii[3], flags);
2751 idx = tp - mol->par->dihedralPars;
2755 tp = ParameterLookupDihedralPar(gBuiltinParameters, t[0], t[1], t[2], t[3], -1, -1, -1, -1, flags);
2757 idx = tp - gBuiltinParameters->dihedralPars;
2762 case kImproperParType: {
2765 tp = ParameterLookupImproperPar(mol->par, t[0], t[1], t[2], t[3], ii[0], ii[1], ii[2], ii[3], flags);
2767 idx = tp - mol->par->improperPars;
2771 tp = ParameterLookupImproperPar(gBuiltinParameters, t[0], t[1], t[2], t[3], -1, -1, -1, -1, flags);
2773 idx = tp - gBuiltinParameters->improperPars;
2781 vp = ParameterLookupVdwPar(mol->par, t[0], flags);
2783 idx = vp - mol->par->vdwPars;
2787 vp = ParameterLookupVdwPar(gBuiltinParameters, t[0], flags);
2789 idx = vp - gBuiltinParameters->vdwPars;
2794 case kVdwPairParType: {
2797 vp = ParameterLookupVdwPairPar(mol->par, t[0], t[1], flags);
2799 idx = vp - mol->par->vdwpPars;
2803 vp = ParameterLookupVdwPairPar(gBuiltinParameters, t[0], t[1], flags);
2805 idx = vp - gBuiltinParameters->vdwpPars;
2814 if ((flags & 256) == 0 || mol == NULL || mol->par == NULL)
2817 /* Insert a new parameter record */
2819 Int count = ParameterGetCountForType(mol->par, parType);
2820 IntGroup *ig = IntGroupNewWithPoints(count, 1, -1);
2821 MolActionCreateAndPerform(mol, gMolActionAddParameters, parType, ig, 0, NULL);
2822 IntGroupRelease(ig);
2825 /* Set atom types */
2826 up = ParameterGetUnionParFromTypeAndIndex(mol->par, parType, idx);
2831 up->bond.type1 = t[0];
2832 up->bond.type2 = t[1];
2835 up->angle.type1 = t[0];
2836 up->angle.type2 = t[1];
2837 up->angle.type3 = t[2];
2839 case kDihedralParType:
2840 case kImproperParType:
2841 up->torsion.type1 = t[0];
2842 up->torsion.type2 = t[1];
2843 up->torsion.type3 = t[2];
2844 up->torsion.type4 = t[3];
2847 up->vdw.type1 = t[0];
2849 case kVdwPairParType:
2850 up->vdwp.type1 = t[0];
2851 up->vdwp.type2 = t[1];
2858 return ValueFromMoleculeWithParameterTypeAndIndex(mol, parType, idx);
2863 * lookup(par_type, atom_types, options, ...) -> ParameterRef
2864 * lookup(par_type, atom_type_string, options, ...) -> ParameterRef
2866 * Find the parameter record that matches the given atom types. The atom types are given
2867 * either as an array of string, or a single string delimited by whitespaces or hyphens.
2868 * Options are given as symbols. Valid values are :global (look for global parameters), :local
2869 * (look for local parameters), :missing (look for missing parameters), :nowildcard (do not
2870 * allow wildcard matching), :nobasetype (the base type does not match for the variant types)
2873 s_Parameter_LookUp(int argc, VALUE *argv, VALUE self)
2876 Molecule *mol = s_MoleculeFromParameterOrParEnumerableValue(self);
2878 rb_raise(rb_eMolbyError, "parameter type and atom types must be specified");
2879 parType = s_ParTypeFromValue(argv[0]);
2880 return s_Parameter_Lookup_sub(argc - 1, argv + 1, parType, mol);
2883 #pragma mark ====== ParEnumerable Class ======
2885 /* The ParEnumerable class encapsulates the Molecule (not Parameter) pointer
2886 and the parameter type. If the Molecule is NULL, then it refers to the
2887 global (built-in) parameters. Note that, even when the Molecule is not NULL,
2888 the global parameters are always accessible. */
2890 typedef struct ParEnumerable {
2892 Int parType; /* Same as parType in ParameterRef */
2895 static ParEnumerable *
2896 s_ParEnumerableNew(Molecule *mol, Int parType)
2898 ParEnumerable *pen = (ParEnumerable *)calloc(sizeof(ParEnumerable), 1);
2902 MoleculeRetain(mol);
2903 pen->parType = parType;
2909 s_ParEnumerableRelease(ParEnumerable *pen)
2912 if (pen->mol != NULL)
2913 MoleculeRelease(pen->mol);
2919 s_MoleculeFromParEnumerableValue(VALUE val)
2922 Data_Get_Struct(val, ParEnumerable, pen);
2927 s_NewParEnumerableValueFromMoleculeAndType(Molecule *mol, Int parType)
2929 ParEnumerable *pen = s_ParEnumerableNew(mol, parType);
2931 rb_raise(rb_eMolbyError, "cannot allocate ParEnumerable record");
2932 return Data_Wrap_Struct(rb_cParEnumerable, 0, (void (*)(void *))s_ParEnumerableRelease, pen);
2937 * par_type -> String
2939 * Get the parameter type, like "bond", "angle", etc.
2942 s_ParEnumerable_ParType(VALUE self) {
2945 Data_Get_Struct(self, ParEnumerable, pen);
2947 if (tp == kElementParType)
2948 return rb_str_new2("element");
2949 tp -= kFirstParType;
2950 if (tp >= 0 && tp < sizeof(s_ParameterTypeNames) / sizeof(s_ParameterTypeNames[0]))
2951 return rb_str_new2(s_ParameterTypeNames[tp]);
2952 else rb_raise(rb_eMolbyError, "Internal error: parameter type tag is out of range (%d)", tp);
2957 * self[idx] -> ParameterRef
2959 * Call the accessor of the Parameter object from which this ParEnumerable object is derived from.
2960 * Thus, if self is "bond" type, self[idx] is equivalent to p.bond(idx), where p is the
2961 * parent Parameter object of self.
2963 * <b>See Also</b>: Parameter#bond, Parameter#angle, Parameter#dihedral, Parameter#improper,
2964 * Parameter#vdw, Parameter#vdw_pair, Parameter#vdw_cutoff, Parameter#element.
2967 s_ParEnumerable_Aref(VALUE self, VALUE ival)
2970 Data_Get_Struct(self, ParEnumerable, pen);
2971 switch (pen->parType) {
2972 /* s_Parameter_XXXX() also accepts ParEnumerable argument */
2973 case kBondParType: return s_Parameter_Bond(self, ival);
2974 case kAngleParType: return s_Parameter_Angle(self, ival);
2975 case kDihedralParType: return s_Parameter_Dihedral(self, ival);
2976 case kImproperParType: return s_Parameter_Improper(self, ival);
2977 case kVdwParType: return s_Parameter_Vdw(self, ival);
2978 case kVdwPairParType: return s_Parameter_VdwPair(self, ival);
2979 case kVdwCutoffParType: return s_Parameter_VdwCutoff(self, ival);
2980 case kElementParType: return s_Parameter_Element(self, ival);
2982 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
2984 return Qnil; /* Not reached */
2991 * Returns the number of parameters included in this enumerable.
2994 s_ParEnumerable_Length(VALUE self)
2997 Data_Get_Struct(self, ParEnumerable, pen);
2998 switch (pen->parType) {
2999 /* s_Parameter_XXXX() also accepts ParEnumerable argument */
3000 case kBondParType: return s_Parameter_Nbonds(self);
3001 case kAngleParType: return s_Parameter_Nangles(self);
3002 case kDihedralParType: return s_Parameter_Ndihedrals(self);
3003 case kImproperParType: return s_Parameter_Nimpropers(self);
3004 case kVdwParType: return s_Parameter_Nvdws(self);
3005 case kVdwPairParType: return s_Parameter_NvdwPairs(self);
3006 case kVdwCutoffParType: return s_Parameter_NvdwCutoffs(self);
3007 case kElementParType: return s_Parameter_Nelements(self);
3009 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3011 return Qnil; /* Not reached */
3018 * Call the block for each parameter, passing a ParameterRef object as a block argument.
3021 s_ParEnumerable_Each(VALUE self)
3027 Data_Get_Struct(self, ParEnumerable, pen);
3028 if (pen->parType == kElementParType)
3029 n = gCountElementParameters;
3031 switch (pen->parType) {
3032 case kBondParType: ofs = offsetof(Parameter, nbondPars); break;
3033 case kAngleParType: ofs = offsetof(Parameter, nanglePars); break;
3034 case kDihedralParType: ofs = offsetof(Parameter, ndihedralPars); break;
3035 case kImproperParType: ofs = offsetof(Parameter, nimproperPars); break;
3036 case kVdwParType: ofs = offsetof(Parameter, nvdwPars); break;
3037 case kVdwPairParType: ofs = offsetof(Parameter, nvdwpPars); break;
3038 case kVdwCutoffParType: ofs = offsetof(Parameter, nvdwCutoffPars); break;
3040 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3042 if (pen->mol == NULL)
3043 n = *((Int *)((char *)gBuiltinParameters + ofs));
3044 else if (pen->mol->par != NULL)
3045 n = *((Int *)((char *)(pen->mol->par) + ofs));
3048 aval = ValueFromMoleculeWithParameterTypeAndIndex(pen->mol, pen->parType, 0);
3049 Data_Get_Struct(aval, ParameterRef, pref);
3050 for (i = 0; i < n; i++) {
3059 * reverse_each {|pref| ...}
3061 * Call the block for each parameter in the reverse order, passing a ParameterRef object as a block argument.
3064 s_ParEnumerable_ReverseEach(VALUE self)
3070 Data_Get_Struct(self, ParEnumerable, pen);
3071 if (pen->parType == kElementParType)
3072 n = gCountElementParameters;
3074 switch (pen->parType) {
3075 case kBondParType: ofs = offsetof(Parameter, nbondPars); break;
3076 case kAngleParType: ofs = offsetof(Parameter, nanglePars); break;
3077 case kDihedralParType: ofs = offsetof(Parameter, ndihedralPars); break;
3078 case kImproperParType: ofs = offsetof(Parameter, nimproperPars); break;
3079 case kVdwParType: ofs = offsetof(Parameter, nvdwPars); break;
3080 case kVdwPairParType: ofs = offsetof(Parameter, nvdwpPars); break;
3081 case kVdwCutoffParType: ofs = offsetof(Parameter, nvdwCutoffPars); break;
3083 rb_raise(rb_eMolbyError, "internal error: unknown parameter type (%d)", pen->parType);
3085 if (pen->mol == NULL)
3086 n = *((Int *)((char *)gBuiltinParameters + ofs));
3087 else if (pen->mol->par != NULL)
3088 n = *((Int *)((char *)(pen->mol->par) + ofs));
3091 aval = ValueFromMoleculeWithParameterTypeAndIndex(pen->mol, pen->parType, 0);
3092 Data_Get_Struct(aval, ParameterRef, pref);
3093 for (i = n - 1; i >= 0; i--) {
3102 * insert(idx = nil, pref = nil) -> ParameterRef
3104 * Insert a new parameter at the specified position (if idx is nil, then at the end).
3105 * If a ParameterRef is given, then the content of the parameter is copied to the new parameter,
3106 * and the parameter is set as molecule-local. Otherwise, the new parameter is blank, and the
3107 * parameter is left undefined.
3108 * Throws an exception if ParEnumerable points to the global parameter.
3111 s_ParEnumerable_Insert(int argc, VALUE *argv, VALUE self)
3119 Data_Get_Struct(self, ParEnumerable, pen);
3120 if (pen->mol == NULL)
3121 rb_raise(rb_eMolbyError, "the global parameters cannot be modified");
3122 n = ParameterGetCountForType(pen->mol->par, pen->parType);
3123 rb_scan_args(argc, argv, "02", &ival, &pval);
3125 i = NUM2INT(rb_Integer(ival));
3127 rb_raise(rb_eMolbyError, "the parameter index (%d) out of range (should be 0..%d)", i, n);
3132 UnionPar *up = s_UnionParFromValue(pval, &type, 0);
3133 if (up == NULL || type != pen->parType)
3134 rb_raise(rb_eMolbyError, "the parameter specification is not correct");
3135 ParameterCopyOneWithType(&u, up, pen->parType);
3138 memset(&u, 0, sizeof(u));
3141 ig = IntGroupNewWithPoints(n, 1, -1);
3142 ParameterInsert(pen->mol->par, pen->parType, &u, ig);
3144 act = MolActionNew(gMolActionDeleteParameters, pen->parType, ig);
3145 MolActionCallback_registerUndo(pen->mol, act);
3146 MolActionRelease(act);
3148 IntGroupRelease(ig);
3149 return ValueFromMoleculeWithParameterTypeAndIndex(pen->mol, pen->parType, n);
3157 * Delete the parameter(s) specified by the argument.
3160 s_ParEnumerable_Delete(VALUE self, VALUE ival)
3165 Data_Get_Struct(self, ParEnumerable, pen);
3166 if (pen->mol == NULL)
3167 rb_raise(rb_eMolbyError, "the global parameters cannot be modified");
3168 n = ParameterGetCountForType(pen->mol->par, pen->parType);
3169 if (rb_obj_is_kind_of(ival, rb_cInteger)) {
3170 ig = IntGroupNewWithPoints(NUM2INT(ival), 1, -1);
3173 ig = IntGroupFromValue(ival);
3174 if ((i = IntGroupGetCount(ig)) == 0) {
3175 IntGroupRelease(ig);
3179 if ((i = IntGroupGetNthPoint(ig, i - 1)) >= n)
3180 rb_raise(rb_eMolbyError, "the parameter index (%d) out of range (should be 0..%d)", i, n);
3183 MolActionCreateAndPerform(pen->mol, gMolActionDeleteParameters, pen->parType, ig);
3184 IntGroupRelease(ig);
3190 * lookup(atom_types, options, ...) -> ParameterRef
3191 * lookup(atom_type_string, options, ...) -> ParameterRef
3193 * Find the parameter record that matches the given atom types. The arguments are
3194 * the same as Parameter#lookup, except for the parameter type which is implicitly
3198 s_ParEnumerable_LookUp(int argc, VALUE *argv, VALUE self)
3201 Data_Get_Struct(self, ParEnumerable, pen);
3202 return s_Parameter_Lookup_sub(argc, argv, pen->parType, pen->mol);
3205 #pragma mark ====== AtomRef Class ======
3207 /* Forward declaration for register undo */
3208 static VALUE s_Molecule_RegisterUndo(int argc, VALUE *argv, VALUE self);
3210 /* Ruby string "set_atom_attr" */
3211 static VALUE s_SetAtomAttrString;
3214 s_AtomIndexFromValue(VALUE self, Atom **app, Molecule **mpp)
3218 Data_Get_Struct(self, AtomRef, aref);
3219 idx = (aref->idx >= 0 ? aref->idx : aref->mol->natoms + aref->idx);
3220 if (idx < 0 || idx >= aref->mol->natoms)
3221 rb_raise(rb_eMolbyError, "atom index out of range (%d; should be %d..%d)", aref->idx, -aref->mol->natoms, aref->mol->natoms - 1);
3223 *app = aref->mol->atoms + idx;
3230 s_AtomFromValue(VALUE self)
3233 s_AtomIndexFromValue(self, &ap, NULL);
3238 s_AtomAndMoleculeFromValue(VALUE self, Molecule **mpp)
3241 s_AtomIndexFromValue(self, &ap, mpp);
3246 s_NotifyModificationForAtomRef(VALUE self)
3249 Data_Get_Struct(self, AtomRef, aref);
3250 MoleculeIncrementModifyCount(aref->mol);
3254 s_RegisterUndoForAtomAttrChange(VALUE self, VALUE key, VALUE val, VALUE oldval)
3257 Data_Get_Struct(self, AtomRef, aref);
3258 if (MolActionCallback_isUndoRegistrationEnabled(aref->mol) && !RTEST(rb_funcall(val, s_ID_equal, 1, oldval))) {
3261 act = MolActionNew(SCRIPT_ACTION("rrr"), "set_atom_attr", INT2NUM(aref->idx), key, oldval);
3262 MolActionCallback_registerUndo(aref->mol, act);
3263 MoleculeCallback_notifyModification(aref->mol, 0);
3264 /* Request MD rebuilt if necessary */
3265 if (key == s_AtomTypeSym || key == s_ChargeSym || key == s_WeightSym || key == s_FixPosSym || key == s_FixForceSym)
3266 aref->mol->needsMDRebuild = 1;
3271 ValueFromMoleculeAndIndex(Molecule *mol, int idx)
3274 aref = AtomRefNew(mol, idx);
3275 return Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
3279 s_AtomRef_GetMolecule(VALUE self)
3282 s_AtomIndexFromValue(self, NULL, &mpp);
3283 return ValueFromMolecule(mpp);
3286 static VALUE s_AtomRef_GetIndex(VALUE self) {
3287 return INT2NUM(s_AtomIndexFromValue(self, NULL, NULL));
3290 static VALUE s_AtomRef_GetSegSeq(VALUE self) {
3291 return INT2NUM(s_AtomFromValue(self)->segSeq);
3294 static VALUE s_AtomRef_GetSegName(VALUE self) {
3295 char *p = s_AtomFromValue(self)->segName;
3296 return rb_str_new(p, strlen_limit(p, 4));
3299 static VALUE s_AtomRef_GetResSeq(VALUE self) {
3300 return INT2NUM(s_AtomFromValue(self)->resSeq);
3303 static VALUE s_AtomRef_GetResName(VALUE self) {
3304 char *p = s_AtomFromValue(self)->resName;
3305 return rb_str_new(p, strlen_limit(p, 4));
3308 static VALUE s_AtomRef_GetName(VALUE self) {
3309 char *p = s_AtomFromValue(self)->aname;
3310 return rb_str_new(p, strlen_limit(p, 4));
3313 static VALUE s_AtomRef_GetAtomType(VALUE self) {
3314 int type = s_AtomFromValue(self)->type;
3315 char *p = (type == 0 ? "" : AtomTypeDecodeToString(type, NULL));
3316 return rb_str_new(p, strlen_limit(p, 6));
3319 static VALUE s_AtomRef_GetCharge(VALUE self) {
3320 return rb_float_new(s_AtomFromValue(self)->charge);
3323 static VALUE s_AtomRef_GetWeight(VALUE self) {
3324 return rb_float_new(s_AtomFromValue(self)->weight);
3327 static VALUE s_AtomRef_GetElement(VALUE self) {
3328 char *p = s_AtomFromValue(self)->element;
3329 return rb_str_new(p, strlen_limit(p, 4));
3332 static VALUE s_AtomRef_GetAtomicNumber(VALUE self) {
3333 return INT2NUM(s_AtomFromValue(self)->atomicNumber);
3336 static VALUE s_AtomRef_GetConnects(VALUE self) {
3339 Atom *ap = s_AtomFromValue(self);
3340 retval = rb_ary_new();
3341 cp = AtomConnectData(&ap->connect);
3342 for (i = 0; i < ap->connect.count; i++)
3343 rb_ary_push(retval, INT2NUM(cp[i]));
3347 static VALUE s_AtomRef_GetR(VALUE self) {
3348 return ValueFromVector(&(s_AtomFromValue(self)->r));
3351 static VALUE s_AtomRef_GetX(VALUE self) {
3352 return rb_float_new(s_AtomFromValue(self)->r.x);
3355 static VALUE s_AtomRef_GetY(VALUE self) {
3356 return rb_float_new(s_AtomFromValue(self)->r.y);
3359 static VALUE s_AtomRef_GetZ(VALUE self) {
3360 return rb_float_new(s_AtomFromValue(self)->r.z);
3363 static Vector s_AtomRef_GetFractionalRAsVector(VALUE self) {
3367 s_AtomIndexFromValue(self, &ap, &mp);
3369 if (mp->cell != NULL)
3370 TransformVec(&r1, mp->cell->rtr, &r1);
3374 static VALUE s_AtomRef_GetFractionalR(VALUE self) {
3375 Vector r1 = s_AtomRef_GetFractionalRAsVector(self);
3376 return ValueFromVector(&r1);
3379 static VALUE s_AtomRef_GetFractionalX(VALUE self) {
3380 return rb_float_new(s_AtomRef_GetFractionalRAsVector(self).x);
3383 static VALUE s_AtomRef_GetFractionalY(VALUE self) {
3384 return rb_float_new(s_AtomRef_GetFractionalRAsVector(self).y);
3387 static VALUE s_AtomRef_GetFractionalZ(VALUE self) {
3388 return rb_float_new(s_AtomRef_GetFractionalRAsVector(self).z);
3391 static VALUE s_AtomRef_GetSigma(VALUE self) {
3392 return ValueFromVector(&(s_AtomFromValue(self)->sigma));
3395 static VALUE s_AtomRef_GetSigmaX(VALUE self) {
3396 return rb_float_new(s_AtomFromValue(self)->sigma.x);
3399 static VALUE s_AtomRef_GetSigmaY(VALUE self) {
3400 return rb_float_new(s_AtomFromValue(self)->sigma.y);
3403 static VALUE s_AtomRef_GetSigmaZ(VALUE self) {
3404 return rb_float_new(s_AtomFromValue(self)->sigma.z);
3407 static VALUE s_AtomRef_GetV(VALUE self) {
3408 return ValueFromVector(&(s_AtomFromValue(self)->v));
3411 static VALUE s_AtomRef_GetF(VALUE self) {
3412 return ValueFromVector(&(s_AtomFromValue(self)->f));
3415 static VALUE s_AtomRef_GetOccupancy(VALUE self) {
3416 return rb_float_new(s_AtomFromValue(self)->occupancy);
3419 static VALUE s_AtomRef_GetTempFactor(VALUE self) {
3420 return rb_float_new(s_AtomFromValue(self)->tempFactor);
3423 static VALUE s_AtomRef_GetAniso(VALUE self) {
3426 Atom *ap = s_AtomFromValue(self);
3427 if (ap->aniso == NULL)
3429 retval = rb_ary_new();
3430 for (i = 0; i < 6; i++)
3431 rb_ary_push(retval, rb_float_new(ap->aniso->bij[i]));
3432 if (ap->aniso->has_bsig) {
3433 rb_ary_push(retval, INT2NUM(0));
3434 for (i = 0; i < 6; i++)
3435 rb_ary_push(retval, rb_float_new(ap->aniso->bsig[i]));
3440 static VALUE s_AtomRef_GetSymop(VALUE self) {
3442 Atom *ap = s_AtomFromValue(self);
3443 if (!ap->symop.alive)
3445 retval = rb_ary_new();
3446 rb_ary_push(retval, INT2NUM(ap->symop.sym));
3447 rb_ary_push(retval, INT2NUM(ap->symop.dx));
3448 rb_ary_push(retval, INT2NUM(ap->symop.dy));
3449 rb_ary_push(retval, INT2NUM(ap->symop.dz));
3450 rb_ary_push(retval, INT2NUM(ap->symbase));
3454 static VALUE s_AtomRef_GetIntCharge(VALUE self) {
3455 return INT2NUM(s_AtomFromValue(self)->intCharge);
3458 static VALUE s_AtomRef_GetFixForce(VALUE self) {
3459 return rb_float_new(s_AtomFromValue(self)->fix_force * INTERNAL2KCAL);
3462 static VALUE s_AtomRef_GetFixPos(VALUE self) {
3463 return ValueFromVector(&(s_AtomFromValue(self)->fix_pos));
3466 static VALUE s_AtomRef_GetExclusion(VALUE self) {
3470 MDExclusion *exinfo;
3473 idx = s_AtomIndexFromValue(self, &ap, &mol);
3474 if (mol->par == NULL || mol->arena == NULL || mol->arena->is_initialized == 0 || mol->needsMDRebuild) {
3475 VALUE mval = ValueFromMolecule(mol);
3476 s_RebuildMDParameterIfNecessary(mval, Qnil);
3478 if (mol->arena->exinfo == NULL)
3480 exinfo = mol->arena->exinfo + idx;
3481 exlist = mol->arena->exlist;
3482 retval = rb_ary_new();
3483 aval = rb_ary_new();
3484 for (i = exinfo->index1; i < exinfo->index2; i++) /* 1-2 exclusion */
3485 rb_ary_push(aval, INT2NUM(exlist[i]));
3486 rb_ary_push(retval, aval);
3487 aval = rb_ary_new();
3488 for (i = exinfo->index2; i < exinfo->index3; i++) /* 1-3 exclusion */
3489 rb_ary_push(aval, INT2NUM(exlist[i]));
3490 rb_ary_push(retval, aval);
3491 aval = rb_ary_new();
3492 for (i = exinfo->index3; i < (exinfo + 1)->index0; i++) /* 1-4 exclusion */
3493 rb_ary_push(aval, INT2NUM(exlist[i]));
3494 rb_ary_push(retval, aval);
3498 static VALUE s_AtomRef_GetMMExclude(VALUE self) {
3499 return INT2NUM(s_AtomFromValue(self)->mm_exclude);
3502 static VALUE s_AtomRef_GetPeriodicExclude(VALUE self) {
3503 return INT2NUM(s_AtomFromValue(self)->periodic_exclude);
3506 static VALUE s_AtomRef_GetHidden(VALUE self) {
3507 return ((s_AtomFromValue(self)->exflags & kAtomHiddenFlag) != 0 ? Qtrue : Qfalse);
3510 static VALUE s_AtomRef_GetAnchorList(VALUE self) {
3513 Atom *ap = s_AtomFromValue(self);
3514 if (ap->anchor == NULL)
3516 count = ap->anchor->connect.count;
3517 retval = rb_ary_new2(count * 2);
3518 cp = AtomConnectData(&ap->anchor->connect);
3519 for (i = 0; i < count; i++) {
3520 rb_ary_store(retval, i, INT2NUM(cp[i]));
3521 rb_ary_store(retval, i + count, rb_float_new(ap->anchor->coeffs[i]));
3526 static VALUE s_AtomRef_SetIndex(VALUE self, VALUE val) {
3527 rb_raise(rb_eMolbyError, "index cannot be directly set");
3531 static VALUE s_AtomRef_SetSegSeq(VALUE self, VALUE val) {
3532 VALUE oval = s_AtomRef_GetSegSeq(self);
3533 val = rb_Integer(val);
3534 s_AtomFromValue(self)->segSeq = NUM2INT(val);
3535 s_RegisterUndoForAtomAttrChange(self, s_SegSeqSym, val, oval);
3539 static VALUE s_AtomRef_SetSegName(VALUE self, VALUE val) {
3540 char *p = StringValuePtr(val);
3541 VALUE oval = s_AtomRef_GetSegName(self);
3542 strncpy(s_AtomFromValue(self)->segName, p, 4);
3543 s_RegisterUndoForAtomAttrChange(self, s_SegNameSym, val, oval);
3547 static VALUE s_AtomRef_SetResSeqOrResName(VALUE self, VALUE val) {
3548 rb_raise(rb_eMolbyError, "residue number/names cannot be directly set. Use Molecule#assign_residue instead.");
3549 return val; /* Not reached */
3552 static VALUE s_AtomRef_SetName(VALUE self, VALUE val) {
3553 Atom *ap = s_AtomFromValue(self);
3554 char *p = StringValuePtr(val);
3555 VALUE oval = s_AtomRef_GetName(self);
3556 if (ap->anchor != NULL && p[0] == '_')
3557 rb_raise(rb_eMolbyError, "please avoid a name beginning with '_' for a pi anchor, because it causes some internal confusion.");
3558 strncpy(ap->aname, p, 4);
3559 s_RegisterUndoForAtomAttrChange(self, s_NameSym, val, oval);
3563 static VALUE s_AtomRef_SetAtomType(VALUE self, VALUE val) {
3565 char *p = StringValuePtr(val);
3566 VALUE oval = s_AtomRef_GetAtomType(self);
3567 int type = (p[0] == 0 ? 0 : AtomTypeEncodeToUInt(p));
3568 if (type != 0 && type < kAtomTypeMinimum)
3569 rb_raise(rb_eMolbyError, "Invalid atom type '%s'", p);
3570 s_AtomAndMoleculeFromValue(self, &mp)->type = type;
3571 mp->needsMDRebuild = 1;
3572 s_RegisterUndoForAtomAttrChange(self, s_AtomTypeSym, val, oval);
3576 static VALUE s_AtomRef_SetCharge(VALUE self, VALUE val) {
3578 VALUE oval = s_AtomRef_GetCharge(self);
3579 val = rb_Float(val);
3580 s_AtomAndMoleculeFromValue(self, &mp)->charge = NUM2DBL(val);
3581 mp->needsMDRebuild = 1;
3582 s_RegisterUndoForAtomAttrChange(self, s_ChargeSym, val, oval);
3586 static VALUE s_AtomRef_SetWeight(VALUE self, VALUE val) {
3588 VALUE oval = s_AtomRef_GetWeight(self);
3589 val = rb_Float(val);
3590 s_AtomAndMoleculeFromValue(self, &mp)->weight = NUM2DBL(val);
3591 mp->needsMDRebuild = 1;
3592 s_RegisterUndoForAtomAttrChange(self, s_WeightSym, val, oval);
3596 static VALUE s_AtomRef_SetElement(VALUE self, VALUE val) {
3599 Atom *ap = s_AtomAndMoleculeFromValue(self, &mp);
3600 char *p = StringValuePtr(val);
3601 VALUE oval = s_AtomRef_GetElement(self);
3602 ap->atomicNumber = ElementToInt(p);
3603 ElementToString(ap->atomicNumber, ap->element);
3604 if ((w = WeightForAtomicNumber(ap->atomicNumber)) > 0.0)
3606 s_RegisterUndoForAtomAttrChange(self, s_ElementSym, val, oval);
3607 mp->needsMDRebuild = 1;
3611 static VALUE s_AtomRef_SetAtomicNumber(VALUE self, VALUE val) {
3614 Atom *ap = s_AtomAndMoleculeFromValue(self, &mp);
3615 VALUE oval = s_AtomRef_GetAtomicNumber(self);
3616 val = rb_Integer(val);
3617 ap->atomicNumber = NUM2INT(val);
3618 ElementToString(ap->atomicNumber, ap->element);
3619 if ((w = WeightForAtomicNumber(ap->atomicNumber)) > 0.0)
3621 s_RegisterUndoForAtomAttrChange(self, s_AtomicNumberSym, val, oval);
3622 mp->needsMDRebuild = 1;
3626 static VALUE s_AtomRef_SetConnects(VALUE self, VALUE val) {
3627 rb_raise(rb_eMolbyError, "connection table cannot be directly set. Use Molecule#create_bond instead.");
3628 return val; /* Not reached */
3631 static VALUE s_AtomRef_SetR(VALUE self, VALUE val) {
3634 VALUE oval = s_AtomRef_GetR(self);
3635 VectorFromValue(val, &v);
3636 s_AtomAndMoleculeFromValue(self, &mp)->r = v;
3637 s_RegisterUndoForAtomAttrChange(self, s_RSym, val, oval);
3638 mp->needsMDCopyCoordinates = 1;
3642 static VALUE s_AtomRef_SetX(VALUE self, VALUE val) {
3645 VALUE oval = s_AtomRef_GetX(self);
3646 val = rb_Float(val);
3648 s_AtomAndMoleculeFromValue(self, &mp)->r.x = f;
3649 s_RegisterUndoForAtomAttrChange(self, s_XSym, val, oval);
3650 mp->needsMDCopyCoordinates = 1;
3654 static VALUE s_AtomRef_SetY(VALUE self, VALUE val) {
3657 VALUE oval = s_AtomRef_GetY(self);
3658 val = rb_Float(val);
3660 s_AtomAndMoleculeFromValue(self, &mp)->r.y = f;
3661 s_RegisterUndoForAtomAttrChange(self, s_YSym, val, oval);
3662 mp->needsMDCopyCoordinates = 1;
3666 static VALUE s_AtomRef_SetZ(VALUE self, VALUE val) {
3669 VALUE oval = s_AtomRef_GetZ(self);
3670 val = rb_Float(val);
3672 s_AtomAndMoleculeFromValue(self, &mp)->r.z = f;
3673 s_RegisterUndoForAtomAttrChange(self, s_ZSym, val, oval);
3674 mp->needsMDCopyCoordinates = 1;
3678 static VALUE s_AtomRef_SetFractionalR(VALUE self, VALUE val) {
3682 s_AtomIndexFromValue(self, &ap, &mp);
3684 VectorFromValue(val, &v);
3685 if (mp->cell != NULL)
3686 TransformVec(&v, mp->cell->tr, &v);
3688 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3689 mp->needsMDCopyCoordinates = 1;
3693 static VALUE s_AtomRef_SetFractionalX(VALUE self, VALUE val) {
3698 s_AtomIndexFromValue(self, &ap, &mp);
3700 val = rb_Float(val);
3702 if (mp->cell != NULL) {
3703 TransformVec(&v, mp->cell->rtr, &v);
3705 TransformVec(&v, mp->cell->tr, &v);
3708 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3709 mp->needsMDCopyCoordinates = 1;
3713 static VALUE s_AtomRef_SetFractionalY(VALUE self, VALUE val) {
3718 s_AtomIndexFromValue(self, &ap, &mp);
3720 val = rb_Float(val);
3722 if (mp->cell != NULL) {
3723 TransformVec(&v, mp->cell->rtr, &v);
3725 TransformVec(&v, mp->cell->tr, &v);
3728 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3729 mp->needsMDCopyCoordinates = 1;
3733 static VALUE s_AtomRef_SetFractionalZ(VALUE self, VALUE val) {
3738 s_AtomIndexFromValue(self, &ap, &mp);
3740 val = rb_Float(val);
3742 if (mp->cell != NULL) {
3743 TransformVec(&v, mp->cell->rtr, &v);
3745 TransformVec(&v, mp->cell->tr, &v);
3748 s_RegisterUndoForAtomAttrChange(self, s_RSym, Qnil, ValueFromVector(&ov));
3749 mp->needsMDCopyCoordinates = 1;
3753 static VALUE s_AtomRef_SetSigma(VALUE self, VALUE val) {
3756 VALUE oval = s_AtomRef_GetSigma(self);
3757 VectorFromValue(val, &v);
3758 s_AtomAndMoleculeFromValue(self, &mp)->sigma = v;
3759 s_RegisterUndoForAtomAttrChange(self, s_SigmaSym, val, oval);
3760 mp->needsMDCopyCoordinates = 1;
3764 static VALUE s_AtomRef_SetSigmaX(VALUE self, VALUE val) {
3767 VALUE oval = s_AtomRef_GetSigmaX(self);
3768 val = rb_Float(val);
3770 s_AtomAndMoleculeFromValue(self, &mp)->sigma.x = f;
3771 s_RegisterUndoForAtomAttrChange(self, s_SigmaXSym, val, oval);
3772 mp->needsMDCopyCoordinates = 1;
3776 static VALUE s_AtomRef_SetSigmaY(VALUE self, VALUE val) {
3779 VALUE oval = s_AtomRef_GetSigmaY(self);
3780 val = rb_Float(val);
3782 s_AtomAndMoleculeFromValue(self, &mp)->sigma.y = f;
3783 s_RegisterUndoForAtomAttrChange(self, s_SigmaYSym, val, oval);
3784 mp->needsMDCopyCoordinates = 1;
3788 static VALUE s_AtomRef_SetSigmaZ(VALUE self, VALUE val) {
3791 VALUE oval = s_AtomRef_GetSigmaZ(self);
3792 val = rb_Float(val);
3794 s_AtomAndMoleculeFromValue(self, &mp)->sigma.z = f;
3795 s_RegisterUndoForAtomAttrChange(self, s_SigmaZSym, val, oval);
3796 mp->needsMDCopyCoordinates = 1;
3800 static VALUE s_AtomRef_SetV(VALUE self, VALUE val) {
3804 VALUE oval = s_AtomRef_GetV(self);
3805 VectorFromValue(val, &v);
3806 s_AtomIndexFromValue(self, &ap, &mp);
3808 s_RegisterUndoForAtomAttrChange(self, s_VSym, val, oval);
3809 mp->needsMDCopyCoordinates = 1;
3813 static VALUE s_AtomRef_SetF(VALUE self, VALUE val) {
3816 VALUE oval = s_AtomRef_GetF(self);
3817 VectorFromValue(val, &v);
3818 s_AtomAndMoleculeFromValue(self, &mp)->f = v;
3819 s_RegisterUndoForAtomAttrChange(self, s_FSym, val, oval);
3820 mp->needsMDCopyCoordinates = 1;
3824 static VALUE s_AtomRef_SetOccupancy(VALUE self, VALUE val) {
3825 VALUE oval = s_AtomRef_GetOccupancy(self);
3827 val = rb_Float(val);
3828 s_AtomAndMoleculeFromValue(self, &mp)->occupancy = NUM2DBL(val);
3829 s_RegisterUndoForAtomAttrChange(self, s_OccupancySym, val, oval);
3830 mp->needsMDCopyCoordinates = 1; /* Occupancy can be used to exclude particular atoms from MM/MD */
3834 static VALUE s_AtomRef_SetTempFactor(VALUE self, VALUE val) {
3835 VALUE oval = s_AtomRef_GetTempFactor(self);
3836 val = rb_Float(val);
3837 s_AtomFromValue(self)->tempFactor = NUM2DBL(val);
3838 s_RegisterUndoForAtomAttrChange(self, s_TempFactorSym, val, oval);
3842 static VALUE s_AtomRef_SetAniso(VALUE self, VALUE val) {
3847 VALUE oval = s_AtomRef_GetAniso(self);
3848 Data_Get_Struct(self, AtomRef, aref);
3849 val = rb_funcall(val, rb_intern("to_a"), 0);
3850 n = RARRAY_LEN(val);
3851 valp = RARRAY_PTR(val);
3852 for (i = 0; i < 6; i++) {
3854 f[i] = NUM2DBL(rb_Float(valp[i]));
3858 type = NUM2INT(rb_Integer(valp[6]));
3861 for (i = 0; i < 6; i++)
3862 f[i + 6] = NUM2DBL(rb_Float(valp[i + 7]));
3864 for (i = 0; i < 6; i++)
3867 i = s_AtomIndexFromValue(self, NULL, NULL);
3868 MoleculeSetAniso(aref->mol, i, type, f[0], f[1], f[2], f[3], f[4], f[5], (n >= 13 ? f + 6 : NULL));
3869 s_RegisterUndoForAtomAttrChange(self, s_AnisoSym, val, oval);
3873 static VALUE s_AtomRef_SetSymop(VALUE self, VALUE val) {
3879 VALUE oval = s_AtomRef_GetSymop(self);
3880 i = s_AtomIndexFromValue(self, &ap, &mol);
3882 ival[0] = ival[1] = ival[2] = ival[3] = ival[4] = 0;
3884 val = rb_funcall(val, rb_intern("to_a"), 0);
3885 n = RARRAY_LEN(val);
3886 valp = RARRAY_PTR(val);
3887 for (i = 0; i < 5; i++) {
3889 if (valp[i] == Qnil)
3892 ival[i] = NUM2INT(rb_Integer(valp[i]));
3893 } else ival[i] = -100000;
3896 if (ival[0] != -100000 && (ival[0] < 0 || ival[0] >= mol->nsyms))
3897 rb_raise(rb_eMolbyError, "index of symmetry (%d) is out of range (should be 0..%d)", ival[0], mol->nsyms - 1);
3898 if (ival[4] != -100000 && (ival[4] < 0 || ival[4] >= mol->natoms))
3899 rb_raise(rb_eMolbyError, "atom index number (%d) is out of range (should be 0..%d)", ival[4], mol->natoms - 1);
3900 if (ap->symop.sym == ival[0] && ap->symop.dx == ival[1] && ap->symop.dy == ival[2] && ap->symop.dz == ival[3])
3901 return val; /* No need to change */
3902 if (ival[0] != -100000)
3903 ap->symop.sym = ival[0];
3904 if (ival[1] != -100000)
3905 ap->symop.dx = ival[1];
3906 if (ival[2] != -100000)
3907 ap->symop.dy = ival[2];
3908 if (ival[3] != -100000)
3909 ap->symop.dz = ival[3];
3910 ap->symop.alive = (SYMOP_ALIVE(ap->symop) != 0);
3911 if (ival[4] != -100000)
3912 ap->symbase = ival[4];
3913 if (ap->symop.alive && (ap->aniso != NULL || (ATOM_AT_INDEX(mol->atoms, ap->symbase))->aniso != NULL)) {
3914 /* The anisotropic parameters should be recalculated */
3915 VALUE oaval = s_AtomRef_GetAniso(self);
3916 MoleculeSetAnisoBySymop(mol, i);
3917 s_RegisterUndoForAtomAttrChange(self, s_AnisoSym, val, oaval);
3919 s_RegisterUndoForAtomAttrChange(self, s_SymopSym, val, oval);
3923 static VALUE s_AtomRef_SetIntCharge(VALUE self, VALUE val) {
3924 VALUE oval = s_AtomRef_GetIntCharge(self);
3925 val = rb_Integer(val);
3926 s_AtomFromValue(self)->intCharge = NUM2INT(val);
3927 s_RegisterUndoForAtomAttrChange(self, s_IntChargeSym, val, oval);
3931 static VALUE s_AtomRef_SetFixForce(VALUE self, VALUE val) {
3933 VALUE oval = s_AtomRef_GetFixForce(self);
3934 val = rb_Float(val);
3935 s_AtomAndMoleculeFromValue(self, &mp)->fix_force = NUM2DBL(val) * KCAL2INTERNAL;
3936 s_RegisterUndoForAtomAttrChange(self, s_FixForceSym, val, oval);
3937 mp->needsMDRebuild = 1;
3941 static VALUE s_AtomRef_SetFixPos(VALUE self, VALUE val) {
3944 VALUE oval = s_AtomRef_GetFixPos(self);
3945 VectorFromValue(val, &v);
3946 s_AtomAndMoleculeFromValue(self, &mp)->fix_pos = v;
3947 s_RegisterUndoForAtomAttrChange(self, s_FixPosSym, val, oval);
3948 mp->needsMDRebuild = 1;
3952 static VALUE s_AtomRef_SetExclusion(VALUE self, VALUE val) {
3953 rb_raise(rb_eMolbyError, "exclusion table is read-only.");
3954 return val; /* Not reached */
3957 static VALUE s_AtomRef_SetMMExclude(VALUE self, VALUE val) {
3958 VALUE oval = s_AtomRef_GetIntCharge(self);
3959 val = rb_Integer(val);
3960 s_AtomFromValue(self)->mm_exclude = NUM2INT(val);
3961 s_RegisterUndoForAtomAttrChange(self, s_MMExcludeSym, val, oval);
3965 static VALUE s_AtomRef_SetPeriodicExclude(VALUE self, VALUE val) {
3966 VALUE oval = s_AtomRef_GetIntCharge(self);
3967 val = rb_Integer(val);
3968 s_AtomFromValue(self)->periodic_exclude = NUM2INT(val);
3969 s_RegisterUndoForAtomAttrChange(self, s_PeriodicExcludeSym, val, oval);
3973 static VALUE s_AtomRef_SetHidden(VALUE self, VALUE val) {
3974 Atom *ap = s_AtomFromValue(self);
3975 VALUE oval = ((ap->exflags & kAtomHiddenFlag) != 0 ? Qtrue : Qfalse);
3977 ap->exflags |= kAtomHiddenFlag;
3979 ap->exflags &= ~kAtomHiddenFlag;
3981 s_RegisterUndoForAtomAttrChange(self, s_HiddenSym, val, oval);
3985 static VALUE s_AtomRef_SetAnchorList(VALUE self, VALUE val) {
3986 Int idx, i, j, k, n, *ip;
3993 MolAction **undoActions;
3994 memset(&ac, 0, sizeof(ac));
3995 idx = s_AtomIndexFromValue(self, &ap, &mol);
3996 oval = s_AtomRef_GetAnchorList(self);
3998 val = rb_ary_to_ary(val);
3999 n = RARRAY_LEN(val);
4002 if (ap->anchor != NULL) {
4003 AtomConnectResize(&ap->anchor->connect, 0);
4004 free(ap->anchor->coeffs);
4007 s_RegisterUndoForAtomAttrChange(self, s_AnchorListSym, val, oval);
4012 rb_raise(rb_eMolbyError, "set_anchor_list: the argument should have at least two atom indices");
4013 if (ap->aname[0] == '_')
4014 rb_raise(rb_eMolbyError, "please avoid a name beginning with '_' for a pi anchor, because it causes some internal confusion.");
4015 ip = (Int *)malloc(sizeof(Int) * n);
4017 for (i = 0; i < n; i++) {
4018 v = RARRAY_PTR(val)[i];
4019 if (rb_obj_is_kind_of(v, rb_cFloat))
4021 j = NUM2INT(rb_Integer(v));
4022 if (j < 0 || j >= mol->natoms)
4023 rb_raise(rb_eMolbyError, "set_anchor_list: atom index (%d) out of range", j);
4024 for (k = 0; k < i; k++) {
4026 rb_raise(rb_eMolbyError, "set_anchor_list: duplicate atom index (%d)", j);
4032 rb_raise(rb_eMolbyError, "set_anchor_list: the argument should have at least two atom indices");
4033 else if (i * 2 != n)
4034 rb_raise(rb_eMolbyError, "set_anchor_list: the weights should be given in the same number as the atom indices");
4035 dp = (Double *)malloc(sizeof(Double) * n / 2);
4036 for (i = 0; i < n / 2; i++) {
4037 dp[i] = NUM2DBL(rb_Float(RARRAY_PTR(val)[i + n / 2]));
4039 rb_raise(rb_eMolbyError, "set_anchor_list: the weights should be positive Floats");
4045 i = MoleculeSetPiAnchorList(mol, idx, n, ip, dp, &nUndoActions, &undoActions);
4049 rb_raise(rb_eMolbyError, "invalid argument");
4050 if (nUndoActions > 0) {
4051 for (i = 0; i < nUndoActions; i++) {
4052 MolActionCallback_registerUndo(mol, undoActions[i]);
4053 MolActionRelease(undoActions[i]);
4057 s_RegisterUndoForAtomAttrChange(self, s_AnchorListSym, val, oval);
4061 static struct s_AtomAttrDef {
4063 VALUE *symref; /* Address of s_IndexSymbol etc. */
4064 ID id; /* Will be set within InitMolby() */
4065 VALUE (*getter)(VALUE);
4066 VALUE (*setter)(VALUE, VALUE);
4067 } s_AtomAttrDefTable[] = {
4068 {"index", &s_IndexSym, 0, s_AtomRef_GetIndex, s_AtomRef_SetIndex},
4069 {"seg_seq", &s_SegSeqSym, 0, s_AtomRef_GetSegSeq, s_AtomRef_SetSegSeq},
4070 {"seg_name", &s_SegNameSym, 0, s_AtomRef_GetSegName, s_AtomRef_SetSegName},
4071 {"res_seq", &s_ResSeqSym, 0, s_AtomRef_GetResSeq, s_AtomRef_SetResSeqOrResName},
4072 {"res_name", &s_ResNameSym, 0, s_AtomRef_GetResName, s_AtomRef_SetResSeqOrResName},
4073 {"name", &s_NameSym, 0, s_AtomRef_GetName, s_AtomRef_SetName},
4074 {"atom_type", &s_AtomTypeSym, 0, s_AtomRef_GetAtomType, s_AtomRef_SetAtomType},
4075 {"charge", &s_ChargeSym, 0, s_AtomRef_GetCharge, s_AtomRef_SetCharge},
4076 {"weight", &s_WeightSym, 0, s_AtomRef_GetWeight, s_AtomRef_SetWeight},
4077 {"element", &s_ElementSym, 0, s_AtomRef_GetElement, s_AtomRef_SetElement},
4078 {"atomic_number", &s_AtomicNumberSym,0, s_AtomRef_GetAtomicNumber, s_AtomRef_SetAtomicNumber},
4079 {"connects", &s_ConnectsSym, 0, s_AtomRef_GetConnects, s_AtomRef_SetConnects},
4080 {"r", &s_RSym, 0, s_AtomRef_GetR, s_AtomRef_SetR},
4081 {"x", &s_XSym, 0, s_AtomRef_GetX, s_AtomRef_SetX},
4082 {"y", &s_YSym, 0, s_AtomRef_GetY, s_AtomRef_SetY},
4083 {"z", &s_ZSym, 0, s_AtomRef_GetZ, s_AtomRef_SetZ},
4084 {"fract_r", &s_FractRSym, 0, s_AtomRef_GetFractionalR, s_AtomRef_SetFractionalR},
4085 {"fract_x", &s_FractXSym, 0, s_AtomRef_GetFractionalX, s_AtomRef_SetFractionalX},
4086 {"fract_y", &s_FractYSym, 0, s_AtomRef_GetFractionalY, s_AtomRef_SetFractionalY},
4087 {"fract_z", &s_FractZSym, 0, s_AtomRef_GetFractionalZ, s_AtomRef_SetFractionalZ},
4088 {"sigma", &s_SigmaSym, 0, s_AtomRef_GetSigma, s_AtomRef_SetSigma},
4089 {"sigma_x", &s_SigmaXSym, 0, s_AtomRef_GetSigmaX, s_AtomRef_SetSigmaX},
4090 {"sigma_y", &s_SigmaYSym, 0, s_AtomRef_GetSigmaY, s_AtomRef_SetSigmaY},
4091 {"sigma_z", &s_SigmaZSym, 0, s_AtomRef_GetSigmaZ, s_AtomRef_SetSigmaZ},
4092 {"v", &s_VSym, 0, s_AtomRef_GetV, s_AtomRef_SetV},
4093 {"f", &s_FSym, 0, s_AtomRef_GetF, s_AtomRef_SetF},
4094 {"occupancy", &s_OccupancySym, 0, s_AtomRef_GetOccupancy, s_AtomRef_SetOccupancy},
4095 {"temp_factor", &s_TempFactorSym, 0, s_AtomRef_GetTempFactor, s_AtomRef_SetTempFactor},
4096 {"aniso", &s_AnisoSym, 0, s_AtomRef_GetAniso, s_AtomRef_SetAniso},
4097 {"symop", &s_SymopSym, 0, s_AtomRef_GetSymop, s_AtomRef_SetSymop},
4098 {"int_charge", &s_IntChargeSym, 0, s_AtomRef_GetIntCharge, s_AtomRef_SetIntCharge},
4099 {"fix_force", &s_FixForceSym, 0, s_AtomRef_GetFixForce, s_AtomRef_SetFixForce},
4100 {"fix_pos", &s_FixPosSym, 0, s_AtomRef_GetFixPos, s_AtomRef_SetFixPos},
4101 {"exclusion", &s_ExclusionSym, 0, s_AtomRef_GetExclusion, s_AtomRef_SetExclusion},
4102 {"mm_exclude", &s_MMExcludeSym, 0, s_AtomRef_GetMMExclude, s_AtomRef_SetMMExclude},
4103 {"periodic_exclude", &s_PeriodicExcludeSym, 0, s_AtomRef_GetPeriodicExclude, s_AtomRef_SetPeriodicExclude},
4104 {"hidden", &s_HiddenSym, 0, s_AtomRef_GetHidden, s_AtomRef_SetHidden},
4105 {"anchor_list", &s_AnchorListSym, 0, s_AtomRef_GetAnchorList, s_AtomRef_SetAnchorList},
4106 {NULL} /* Sentinel */
4110 s_AtomRef_SetAttr(VALUE self, VALUE key, VALUE value)
4114 if (TYPE(key) != T_SYMBOL) {
4115 kid = rb_intern(StringValuePtr(key));
4117 } else kid = SYM2ID(key);
4118 for (i = 0; s_AtomAttrDefTable[i].name != NULL; i++) {
4119 if (s_AtomAttrDefTable[i].id == kid) {
4120 if (value == Qundef)
4121 return (*(s_AtomAttrDefTable[i].getter))(self);
4123 return (*(s_AtomAttrDefTable[i].setter))(self, value);
4126 rb_raise(rb_eMolbyError, "unknown atom attribute \"%s\"", rb_id2name(kid));
4127 return Qnil; /* not reached */
4131 s_AtomRef_GetAttr(VALUE self, VALUE key)
4133 return s_AtomRef_SetAttr(self, key, Qundef);
4136 #pragma mark ====== MolEnumerable Class ======
4138 static int s_Molecule_AtomIndexFromValue(Molecule *, VALUE);
4142 * self[idx] -> AtomRef or Array of Integers
4144 * Get the idx-th atom, bond, etc. for the Molecule from which this MolEnuerable object is
4145 * derived from. For the atom, the return value is AtomRef. For the residue, the return
4146 * value is a String. Otherwise, the return value is an Array of Integers.
4149 s_MolEnumerable_Aref(VALUE self, VALUE arg1)
4151 MolEnumerable *mseq;
4154 Data_Get_Struct(self, MolEnumerable, mseq);
4156 if (mseq->kind == kAtomKind) {
4157 return ValueFromMoleculeAndIndex(mol, s_Molecule_AtomIndexFromValue(mol, arg1));
4159 idx1 = NUM2INT(arg1);
4160 switch (mseq->kind) {
4162 idx2 = (idx1 >= 0 ? idx1 : mol->nbonds + idx1);
4163 if (idx2 < 0 || idx2 >= mol->nbonds)
4164 rb_raise(rb_eIndexError, "bond index out of range (%d; should be %d..%d)", idx1, -mol->nbonds, mol->nbonds - 1);
4165 return rb_ary_new3(2, INT2NUM(mol->bonds[idx2 * 2]), INT2NUM(mol->bonds[idx2 * 2 + 1]));
4168 idx2 = (idx1 >= 0 ? idx1 : mol->nangles + idx1);
4169 if (idx2 < 0 || idx2 >= mol->nangles)
4170 rb_raise(rb_eIndexError, "angle index out of range (%d; should be %d..%d)", idx1, -mol->nangles, mol->nangles - 1);
4171 return rb_ary_new3(3, INT2NUM(mol->angles[idx2 * 3]), INT2NUM(mol->angles[idx2 * 3 + 1]), INT2NUM(mol->angles[idx2 * 3 + 2]));
4173 case kDihedralKind: {
4174 idx2 = (idx1 >= 0 ? idx1 : mol->ndihedrals + idx1);
4175 if (idx2 < 0 || idx2 >= mol->ndihedrals)
4176 rb_raise(rb_eIndexError, "dihedral index out of range (%d; should be %d..%d)", idx1, -mol->ndihedrals, mol->ndihedrals - 1);
4177 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]));
4179 case kImproperKind: {
4180 idx2 = (idx1 >= 0 ? idx1 : mol->nimpropers + idx1);
4181 if (idx2 < 0 || idx2 >= mol->nimpropers)
4182 rb_raise(rb_eIndexError, "improper index out of range (%d; should be %d..%d)", idx1, -mol->nimpropers, mol->nimpropers - 1);
4183 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]));
4185 case kResidueKind: {
4187 idx2 = (idx1 >= 0 ? idx1 : mol->nresidues + idx1);
4188 if (idx2 < 0 || idx2 >= mol->nresidues)
4189 rb_raise(rb_eIndexError, "residue index out of range (%d; should be %d..%d)", idx1, -mol->nresidues, mol->nresidues - 1);
4190 p = mol->residues[idx2];
4191 return rb_str_new(p, strlen_limit(p, 4));
4201 * Returns the number of objects included in this enumerable.
4204 s_MolEnumerable_Length(VALUE self)
4206 MolEnumerable *mseq;
4207 Data_Get_Struct(self, MolEnumerable, mseq);
4208 switch (mseq->kind) {
4210 return INT2NUM(mseq->mol->natoms);
4212 return INT2NUM(mseq->mol->nbonds);
4214 return INT2NUM(mseq->mol->nangles);
4216 return INT2NUM(mseq->mol->ndihedrals);
4218 return INT2NUM(mseq->mol->nimpropers);
4220 return INT2NUM(mseq->mol->nresidues);
4229 * Call the block for each atom/bond/angle/dihedral/improper/residue. The block argument is
4230 * an AtomRef for atoms, a String for residues, and an Array of Integers for others.
4231 * For the atoms, a same AtomRef object is passed (with different internal information)
4232 * for each invocation of block. Otherwise, a new Ruby object will be created and passed
4233 * for each iteration.
4236 s_MolEnumerable_Each(VALUE self)
4238 MolEnumerable *mseq;
4240 int len = NUM2INT(s_MolEnumerable_Length(self));
4241 Data_Get_Struct(self, MolEnumerable, mseq);
4242 if (mseq->kind == kAtomKind) {
4243 /* The same AtomRef object will be used during the loop */
4244 AtomRef *aref = AtomRefNew(mseq->mol, 0);
4245 VALUE arval = Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
4246 for (i = 0; i < len; i++) {
4251 /* A new ruby object will be created at each iteration (not very efficient) */
4252 for (i = 0; i < len; i++) {
4253 rb_yield(s_MolEnumerable_Aref(self, INT2NUM(i)));
4259 #pragma mark ====== Molecule Class ======
4261 /* An malloc'ed string buffer. Retains the error/warning message from the last ***load/***save method. */
4262 /* Accessible from Ruby as Molecule#error_message and Molecule#error_message=. */
4263 char *gLoadSaveErrorMessage = NULL;
4265 #define MoleculeClearLoadSaveErrorMessage() (gLoadSaveErrorMessage != NULL ? (free(gLoadSaveErrorMessage), gLoadSaveErrorMessage = NULL) : NULL)
4268 MoleculeFromValue(VALUE val)
4271 if (!rb_obj_is_kind_of(val, rb_cMolecule))
4272 rb_raise(rb_eMolbyError, "Molecule instance is expected");
4273 Data_Get_Struct(val, Molecule, mol);
4277 static VALUE sMoleculeRetainArray = Qnil;
4279 /* The function is called from MoleculeRelease() */
4280 /* The Ruby Molecule object is held as mol->exmolobj, and is also protected from */
4281 /* GC by registering in the sMoleculeRetainArray. This causes the same Ruby */
4282 /* object is always returned for the same Molecule. */
4283 /* When the reference count of the Molecule becomes 1, then the Ruby object is */
4284 /* removed from sMoleculeRetainArray. In this situation, the Molecule is retained */
4285 /* only by the currently alive Ruby containers. When the Ruby Molecule object is */
4286 /* removed from all alive Ruby containers, the Ruby object will be collected by */
4287 /* the next GC invocation, and at that time the Molecule structure is properly released. */
4289 /* Register/unregister the exmolobj Ruby object */
4291 MoleculeReleaseExternalObj(Molecule *mol)
4293 if (mol != NULL && mol->base.refCount <= 2 && mol->exmolobjProtected == 1) {
4294 rb_ary_delete(sMoleculeRetainArray, (VALUE)mol->exmolobj);
4295 mol->exmolobjProtected = 0;
4300 MoleculeRetainExternalObj(Molecule *mol)
4302 if (mol != NULL && mol->base.refCount >= 2 && mol->exmolobj != NULL && mol->exmolobjProtected == 0) {
4303 if (sMoleculeRetainArray == Qnil) {
4304 rb_define_readonly_variable("molecules", &sMoleculeRetainArray);
4305 sMoleculeRetainArray = rb_ary_new();
4308 rb_ary_push(sMoleculeRetainArray, (VALUE)mol->exmolobj);
4309 mol->exmolobjProtected = 1;
4313 /* Release hook function for Ruby */
4315 MoleculeReleaseHook(Molecule *mol)
4317 if (mol->exmolobj != NULL) {
4318 /* No need to remove from sMoleculeRetainArray */
4319 mol->exmolobj = NULL;
4320 mol->exmolobjProtected = 0;
4322 MoleculeRelease(mol);
4326 ValueFromMolecule(Molecule *mol)
4330 if (mol->exmolobj != NULL)
4331 return (VALUE)mol->exmolobj;
4332 mol->exmolobj = (void *)Data_Wrap_Struct(rb_cMolecule, 0, (void (*)(void *))MoleculeReleaseHook, mol);
4333 MoleculeRetain(mol); /* MoleculeRetainExternalObj() is automatically called */
4334 return (VALUE)mol->exmolobj;
4339 s_Molecule_Alloc(VALUE klass)
4342 Molecule *mol = MoleculeNew();
4343 val = ValueFromMolecule(mol);
4344 MoleculeRelease(mol); /* Only the returned Ruby object retains this molecule */
4349 s_Molecule_AtomIndexFromValue(Molecule *mol, VALUE val)
4353 if (FIXNUM_P(val)) {
4355 if (n >= 0 && n < mol->natoms)
4357 n = -1; /* No such atom */
4358 val = rb_inspect(val);
4360 n = MoleculeAtomIndexFromString(mol, StringValuePtr(val));
4362 if (n >= 0 && n < mol->natoms)
4365 rb_raise(rb_eMolbyError, "no such atom: %s", p);
4367 rb_raise(rb_eMolbyError, "bad format of atom specification: %s", p);
4369 rb_raise(rb_eMolbyError, "error in converting value to atom index: %s", p);
4370 return 0; /* Not reached */
4374 s_Molecule_AtomGroupFromValue(VALUE self, VALUE val)
4377 val = rb_funcall(self, rb_intern("atom_group"), 1, val);
4378 if (!rb_obj_is_kind_of(val, rb_cIntGroup))
4379 rb_raise(rb_eMolbyError, "IntGroup instance is expected");
4380 Data_Get_Struct(val, IntGroup, ig);
4386 s_Molecule_RaiseOnLoadSave(int status, const char *msg, const char *fname)
4388 if (gLoadSaveErrorMessage != NULL) {
4389 MyAppCallback_setConsoleColor(1);
4390 MyAppCallback_showScriptMessage("On loading %s:\n%s\n", fname, gLoadSaveErrorMessage);
4391 MyAppCallback_setConsoleColor(0);
4394 rb_raise(rb_eMolbyError, "%s %s", msg, fname);
4401 * Duplicate a molecule. All entries are deep copied, so modifying the newly
4402 * created object does not affect the old object in any sense.
4405 s_Molecule_InitCopy(VALUE self, VALUE arg)
4407 Molecule *mp1, *mp2;
4408 Data_Get_Struct(self, Molecule, mp1);
4409 mp2 = MoleculeFromValue(arg);
4410 if (MoleculeInitWithMolecule(mp1, mp2) == NULL)
4411 rb_raise(rb_eMolbyError, "Cannot duplicate molecule");
4417 * loadmbsf(file) -> bool
4419 * Read a structure from a mbsf file.
4420 * Return true if successful.
4423 s_Molecule_Loadmbsf(int argc, VALUE *argv, VALUE self)
4429 MoleculeClearLoadSaveErrorMessage();
4430 Data_Get_Struct(self, Molecule, mol);
4431 rb_scan_args(argc, argv, "1", &fname);
4432 fstr = FileStringValuePtr(fname);
4433 retval = MoleculeLoadMbsfFile(mol, fstr, &gLoadSaveErrorMessage);
4434 s_Molecule_RaiseOnLoadSave(retval, "Failed to load mbsf", fstr);
4440 * loadpsf(file, pdbfile = nil) -> bool
4442 * Read a structure from a psf file. molecule must be empty. The psf may be
4443 * an "extended" version, which also contains coordinates. If pdbfile
4444 * is given, then atomic coordinates are read from that file.
4445 * Return true if successful.
4448 s_Molecule_Loadpsf(int argc, VALUE *argv, VALUE self)
4450 VALUE fname, pdbname;
4451 char *fstr, *pdbstr;
4454 Data_Get_Struct(self, Molecule, mol);
4455 if (mol->natoms > 0)
4456 return Qnil; /* Must be a new molecule */
4457 MoleculeClearLoadSaveErrorMessage();
4458 rb_scan_args(argc, argv, "11", &fname, &pdbname);
4459 fstr = FileStringValuePtr(fname);
4460 retval = MoleculeLoadPsfFile(mol, fstr, &gLoadSaveErrorMessage);
4461 s_Molecule_RaiseOnLoadSave(retval, "Failed to load psf", fstr);
4463 if (!NIL_P(pdbname)) {
4464 pdbstr = strdup(FileStringValuePtr(pdbname));
4465 retval = MoleculeReadCoordinatesFromPdbFile(mol, pdbstr, &gLoadSaveErrorMessage);
4467 s_Molecule_RaiseOnLoadSave(retval, "Failed to load coordinates from pdb", pdbstr);
4474 * loadpdb(file) -> bool
4476 * Read coordinates from a pdb file. If molecule is empty, then structure is build
4477 * by use of CONECT instructions. Otherwise, only the coordinates are read in.
4478 * Return true if successful.
4481 s_Molecule_Loadpdb(int argc, VALUE *argv, VALUE self)
4487 Data_Get_Struct(self, Molecule, mol);
4488 rb_scan_args(argc, argv, "1", &fname);
4489 MoleculeClearLoadSaveErrorMessage();
4490 fstr = FileStringValuePtr(fname);
4491 retval = MoleculeReadCoordinatesFromPdbFile(mol, fstr, &gLoadSaveErrorMessage);
4492 s_Molecule_RaiseOnLoadSave(retval, "Failed to load pdb", fstr);
4498 * loaddcd(file) -> bool
4500 * Read coordinates from a dcd file. The molecule should not empty.
4501 * Return true if successful.
4504 s_Molecule_Loaddcd(int argc, VALUE *argv, VALUE self)
4510 Data_Get_Struct(self, Molecule, mol);
4511 rb_scan_args(argc, argv, "1", &fname);
4512 MoleculeClearLoadSaveErrorMessage();
4513 fstr = FileStringValuePtr(fname);
4514 retval = MoleculeReadCoordinatesFromDcdFile(mol, fstr, &gLoadSaveErrorMessage);
4515 s_Molecule_RaiseOnLoadSave(retval, "Failed to load dcd", fstr);
4521 * loadtep(file) -> bool
4523 * Read coordinates from an ortep .tep file.
4524 * Return true if successful.
4527 s_Molecule_Loadtep(int argc, VALUE *argv, VALUE self)
4533 Data_Get_Struct(self, Molecule, mol);
4534 rb_scan_args(argc, argv, "1", &fname);
4535 MoleculeClearLoadSaveErrorMessage();
4536 fstr = FileStringValuePtr(fname);
4537 retval = MoleculeLoadTepFile(mol, fstr, &gLoadSaveErrorMessage);
4538 s_Molecule_RaiseOnLoadSave(retval, "Failed to load ORTEP file", fstr);
4544 * loadres(file) -> bool
4546 * Read coordinates from a shelx .res file.
4547 * Return true if successful.
4550 s_Molecule_Loadres(int argc, VALUE *argv, VALUE self)
4556 Data_Get_Struct(self, Molecule, mol);
4557 rb_scan_args(argc, argv, "1", &fname);
4558 MoleculeClearLoadSaveErrorMessage();
4559 fstr = FileStringValuePtr(fname);
4560 retval = MoleculeLoadShelxFile(mol, fstr, &gLoadSaveErrorMessage);
4561 s_Molecule_RaiseOnLoadSave(retval, "Failed to load SHELX res file", fstr);
4567 * loadfchk(file) -> bool
4569 * Read coordinates and MO information from a Gaussian fchk file. (TODO: implement this)
4570 * Return true if successful.
4573 s_Molecule_Loadfchk(int argc, VALUE *argv, VALUE self)
4579 Data_Get_Struct(self, Molecule, mol);
4580 rb_scan_args(argc, argv, "1", &fname);
4581 MoleculeClearLoadSaveErrorMessage();
4582 fstr = FileStringValuePtr(fname);
4583 retval = MoleculeLoadGaussianFchkFile(mol, fstr, &gLoadSaveErrorMessage);
4584 s_Molecule_RaiseOnLoadSave(retval, "Failed to load Gaussian fchk", fstr);
4590 * loaddat(file) -> bool
4592 * Read coordinates and ESP information from a GAMESS dat file. (TODO: read MO info as well)
4593 * Return true if successful.
4596 s_Molecule_Loaddat(int argc, VALUE *argv, VALUE self)
4602 Data_Get_Struct(self, Molecule, mol);
4603 rb_scan_args(argc, argv, "1", &fname);
4604 MoleculeClearLoadSaveErrorMessage();
4605 fstr = FileStringValuePtr(fname);
4606 MyAppCallback_showProgressPanel("Loading GAMESS dat file...");
4607 retval = MoleculeLoadGamessDatFile(mol, fstr, &gLoadSaveErrorMessage);
4608 MyAppCallback_hideProgressPanel();
4609 s_Molecule_RaiseOnLoadSave(retval, "Failed to load GAMESS dat", fstr);
4615 * savembsf(file) -> bool
4617 * Write structure as a mbsf file. Returns true if successful.
4620 s_Molecule_Savembsf(VALUE self, VALUE fname)
4625 Data_Get_Struct(self, Molecule, mol);
4626 MoleculeClearLoadSaveErrorMessage();
4627 fstr = FileStringValuePtr(fname);
4628 retval = MoleculeWriteToMbsfFile(mol, fstr, &gLoadSaveErrorMessage);
4629 s_Molecule_RaiseOnLoadSave(retval, "Failed to save mbsf", fstr);
4635 * savepsf(file) -> bool
4637 * Write structure as a psf file. Returns true if successful.
4640 s_Molecule_Savepsf(VALUE self, VALUE fname)
4645 Data_Get_Struct(self, Molecule, mol);
4646 MoleculeClearLoadSaveErrorMessage();
4647 fstr = FileStringValuePtr(fname);
4648 retval = MoleculeWriteToPsfFile(mol, fstr, &gLoadSaveErrorMessage);
4649 s_Molecule_RaiseOnLoadSave(retval, "Failed to save psf", fstr);
4655 * savepdb(file) -> bool
4657 * Write coordinates as a pdb file. Returns true if successful.
4660 s_Molecule_Savepdb(VALUE self, VALUE fname)
4665 Data_Get_Struct(self, Molecule, mol);
4666 MoleculeClearLoadSaveErrorMessage();
4667 fstr = FileStringValuePtr(fname);
4668 retval = MoleculeWriteToPdbFile(mol, fstr, &gLoadSaveErrorMessage);
4669 s_Molecule_RaiseOnLoadSave(retval, "Failed to save pdb", fstr);
4675 * savedcd(file) -> bool
4677 * Write coordinates as a dcd file. Returns true if successful.
4680 s_Molecule_Savedcd(VALUE self, VALUE fname)
4685 Data_Get_Struct(self, Molecule, mol);
4686 MoleculeClearLoadSaveErrorMessage();
4687 fstr = FileStringValuePtr(fname);
4688 retval = MoleculeWriteToDcdFile(mol, fstr, &gLoadSaveErrorMessage);
4689 s_Molecule_RaiseOnLoadSave(retval, "Failed to save dcd", fstr);
4695 * savetep(file) -> bool
4697 * Write coordinates as an ORTEP file. Returns true if successful.
4701 s_Molecule_Savetep(VALUE self, VALUE fname)
4706 Data_Get_Struct(self, Molecule, mol);
4707 fstr = FileStringValuePtr(fname);
4708 if (MoleculeWriteToTepFile(mol, fstr, errbuf, sizeof errbuf) != 0)
4709 rb_raise(rb_eMolbyError, errbuf);
4714 /* load([ftype, ] fname, ...) */
4716 s_Molecule_LoadSave(int argc, VALUE *argv, VALUE self, int loadFlag)
4719 char *argstr, *methname, *p, *type = "";
4722 const char *ls = (loadFlag ? "load" : "save");
4723 int lslen = strlen(ls);
4728 if (argc == 0 || (argstr = StringValuePtr(argv[0])) == NULL)
4729 rb_raise(rb_eMolbyError, "the first argument must be either filename or \":filetype\"");
4730 if (argstr[0] == ':') {
4731 /* Call "loadXXX" (or "saveXXX") for type ":XXX" */
4732 methname = ALLOC_N(char, lslen + strlen(argstr));
4733 strcpy(methname, ls);
4734 strcat(methname, argstr + 1);
4736 for (i = lslen; methname[i] != 0; i++)
4737 methname[i] = tolower(methname[i]);
4738 mid = rb_intern(methname);
4742 rval = rb_funcall2(self, mid, argc, argv);
4748 /* Guess file type from extension */
4749 p = strrchr(argstr, '.');
4753 for (methname = p; *methname != 0; methname++) {
4754 if (!isalpha(*methname))
4757 if (*methname == 0) {
4758 methname = ALLOC_N(char, lslen + strlen(p) + 1);
4759 if (methname == NULL)
4760 rb_raise(rb_eMolbyError, "Low memory");
4761 strcpy(methname, ls);
4762 strcat(methname, p);
4763 for (i = lslen; methname[i] != 0; i++)
4764 methname[i] = tolower(methname[i]);
4765 mid = rb_intern(methname);
4768 if (rb_respond_to(self, mid)) {
4769 /* Load: try to call the load procedure only if it is available */
4770 rval = rb_funcall2(self, mid, argc, argv);
4775 /* Save: call the save procedure, and if not found then call 'method_missing' */
4776 rval = rb_funcall2(self, mid, argc, argv);
4783 rval = rb_str_to_str(argv[0]);
4784 asprintf(&p, "Failed to %s file %s", (loadFlag ? "load" : "save"), type);
4785 s_Molecule_RaiseOnLoadSave(1, p, StringValuePtr(rval));
4786 return Qnil; /* Does not reach here */
4790 /* Register the path */
4793 Data_Get_Struct(self, Molecule, mol);
4794 MoleculeSetPath(mol, StringValuePtr(argv[0]));
4796 /* Check if all occupancy factors are zero; if that is the case, then all set to 1.0 */
4797 /* for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
4798 if (ap->occupancy != 0.0)
4801 if (i == mol->natoms) {
4802 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
4803 ap->occupancy = 1.0;
4812 * molload(file, *args) -> bool
4814 * Read a structure from the given file by calling the public method "loadXXX" (XXX is the
4815 * file type given by the extension). If this method fails, then all defined (public)
4816 * "loadXXX" methods are invoked, and raises an exception if none of them were successful.
4819 s_Molecule_Load(int argc, VALUE *argv, VALUE self)
4821 return s_Molecule_LoadSave(argc, argv, self, 1);
4826 * molsave(file, *args) -> bool
4828 * Write a structure/coordinate to the given file by calling the public method "saveXXX"
4829 * (XXX is the file type given by the extension).
4832 s_Molecule_Save(int argc, VALUE *argv, VALUE self)
4834 return s_Molecule_LoadSave(argc, argv, self, 0);
4841 * Returns the display name of the molecule. If the molecule has no associated
4842 * document, then returns nil.
4845 s_Molecule_Name(VALUE self)
4849 Data_Get_Struct(self, Molecule, mol);
4850 MoleculeCallback_displayName(mol, buf, sizeof buf);
4854 return rb_str_new2(buf);
4859 * set_name(string) -> self
4861 * Set the name of an untitled molecule. If the molecule is not associated with window
4862 * or it already has an associated file, then exception is thrown.
4865 s_Molecule_SetName(VALUE self, VALUE nval)
4868 Data_Get_Struct(self, Molecule, mol);
4869 if (MoleculeCallback_setDisplayName(mol, StringValuePtr(nval)))
4870 rb_raise(rb_eMolbyError, "Cannot change the window title");
4879 * Returns the full path name of the molecule, if it is associated with a file.
4880 * If the molecule has no associated file, then returns nil.
4883 s_Molecule_Path(VALUE self)
4887 Data_Get_Struct(self, Molecule, mol);
4888 MoleculeCallback_pathName(mol, buf, sizeof buf);
4892 return Ruby_NewFileStringValue(buf);
4899 * Returns the full path name of the directory in which the file associated with the
4900 * molecule is located. If the molecule has no associated file, then returns nil.
4903 s_Molecule_Dir(VALUE self)
4907 Data_Get_Struct(self, Molecule, mol);
4908 MoleculeCallback_pathName(mol, buf, sizeof buf);
4910 translate_char(buf, '\\', '/');
4915 p = strrchr(buf, '/');
4918 return rb_str_new2(buf);
4926 * Returns a string in the form "Molecule[name]" if the molecule has the associated
4927 * document. Otherwise, a string "<Molecule:0x****>" (the address is the address of
4928 * the Molecule structure) is returned.
4931 s_Molecule_Inspect(VALUE self)
4935 Data_Get_Struct(self, Molecule, mol);
4936 MoleculeCallback_displayName(mol, buf, sizeof buf);
4938 /* No associated document */
4939 snprintf(buf, sizeof buf, "#<Molecule:0x%lx>", self);
4940 return rb_str_new2(buf);
4942 /* Check whether the document name is duplicate */
4946 for (idx = 0, k = k2 = 0; (mol2 = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
4947 MoleculeCallback_displayName(mol2, buf2, sizeof buf2);
4948 if (strcmp(buf, buf2) == 0) {
4955 snprintf(buf2, sizeof buf2, "Molecule[\"%s\",%d]", buf, k2);
4957 snprintf(buf2, sizeof buf2, "Molecule[\"%s\"]", buf);
4959 return rb_str_new2(buf2);
4966 * open(file) -> Molecule
4968 * Create a new molecule from file as a document. If file is not given, an untitled document is created.
4971 s_Molecule_Open(int argc, VALUE *argv, VALUE self)
4977 rb_scan_args(argc, argv, "01", &fname);
4981 p = FileStringValuePtr(fname);
4982 iflag = Ruby_SetInterruptFlag(Qfalse);
4983 mp = MoleculeCallback_openNewMolecule(p);
4984 Ruby_SetInterruptFlag(iflag);
4987 rb_raise(rb_eMolbyError, "Cannot create untitled document");
4989 rb_raise(rb_eMolbyError, "Cannot open the file %s", p);
4991 return ValueFromMolecule(mp);
4997 * new(file, *args) -> Molecule
4999 * Create a new molecule and call "load" method with the same arguments.
5002 s_Molecule_Initialize(int argc, VALUE *argv, VALUE self)
5005 return s_Molecule_Load(argc, argv, self);
5006 else return Qnil; /* An empty molecule (which is prepared in s_Molecule_Alloc()) is returned */
5010 s_Molecule_MolEnumerable(VALUE self, int kind)
5013 MolEnumerable *mseq;
5014 Data_Get_Struct(self, Molecule, mol);
5015 mseq = MolEnumerableNew(mol, kind);
5016 return Data_Wrap_Struct(rb_cMolEnumerable, 0, (void (*)(void *))MolEnumerableRelease, mseq);
5021 * atoms -> MolEnumerable
5023 * Returns a MolEnumerable object representing the array of atoms.
5026 s_Molecule_Atoms(VALUE self)
5028 return s_Molecule_MolEnumerable(self, kAtomKind);
5033 * bonds -> MolEnumerable
5035 * Returns a MolEnumerable object representing the array of bonds. A bond is represented
5036 * by an array of two atom indices.
5039 s_Molecule_Bonds(VALUE self)
5041 return s_Molecule_MolEnumerable(self, kBondKind);
5046 * angles -> MolEnumerable
5048 * Returns a MolEnumerable object representing the array of angles. An angle is represented
5049 * by an array of three atom indices.
5052 s_Molecule_Angles(VALUE self)
5054 return s_Molecule_MolEnumerable(self, kAngleKind);
5059 * dihedrals -> MolEnumerable
5061 * Returns a MolEnumerable object representing the array of dihedrals. A dihedral is represented
5062 * by an array of four atom indices.
5065 s_Molecule_Dihedrals(VALUE self)
5067 return s_Molecule_MolEnumerable(self, kDihedralKind);
5072 * impropers -> MolEnumerable
5074 * Returns a MolEnumerable object representing the array of impropers. An improper is represented
5075 * by an array of four atom indices.
5078 s_Molecule_Impropers(VALUE self)
5080 return s_Molecule_MolEnumerable(self, kImproperKind);
5085 * residues -> MolEnumerable
5087 * Returns a MolEnumerable object representing the array of residue names.
5090 s_Molecule_Residues(VALUE self)
5092 return s_Molecule_MolEnumerable(self, kResidueKind);
5099 * Returns the number of atoms.
5102 s_Molecule_Natoms(VALUE self)
5105 Data_Get_Struct(self, Molecule, mol);
5106 return INT2NUM(mol->natoms);
5113 * Returns the number of bonds.
5116 s_Molecule_Nbonds(VALUE self)
5119 Data_Get_Struct(self, Molecule, mol);
5120 return INT2NUM(mol->nbonds);
5125 * nangles -> Integer
5127 * Returns the number of angles.
5130 s_Molecule_Nangles(VALUE self)
5133 Data_Get_Struct(self, Molecule, mol);
5134 return INT2NUM(mol->nangles);
5139 * ndihedrals -> Integer
5141 * Returns the number of dihedrals.
5144 s_Molecule_Ndihedrals(VALUE self)
5147 Data_Get_Struct(self, Molecule, mol);
5148 return INT2NUM(mol->ndihedrals);
5153 * nimpropers -> Integer
5155 * Returns the number of impropers.
5158 s_Molecule_Nimpropers(VALUE self)
5161 Data_Get_Struct(self, Molecule, mol);
5162 return INT2NUM(mol->nimpropers);
5167 * nresidues -> Integer
5169 * Returns the number of residues.
5172 s_Molecule_Nresidues(VALUE self)
5175 Data_Get_Struct(self, Molecule, mol);
5176 return INT2NUM(mol->nresidues);
5180 s_Molecule_BondParIsObsolete(VALUE self, VALUE val)
5182 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.");
5187 * bond_par(idx) -> ParameterRef
5189 * Returns the MD parameter for the idx-th bond.
5193 s_Molecule_BondPar(VALUE self, VALUE val)
5200 Data_Get_Struct(self, Molecule, mol);
5201 ival = NUM2INT(rb_Integer(val));
5202 if (ival < -mol->nbonds || ival >= mol->nbonds)
5203 rb_raise(rb_eMolbyError, "bond index (%d) out of range", ival);
5205 ival += mol->nbonds;
5206 s_RebuildMDParameterIfNecessary(self, Qtrue);
5207 i1 = mol->bonds[ival * 2];
5208 i2 = mol->bonds[ival * 2 + 1];
5209 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5210 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5211 bp = ParameterLookupBondPar(mol->par, t1, t2, i1, i2, 0);
5214 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kBondParType, bp - mol->par->bondPars);
5220 * angle_par(idx) -> ParameterRef
5222 * Returns the MD parameter for the idx-th angle.
5226 s_Molecule_AnglePar(VALUE self, VALUE val)
5233 Data_Get_Struct(self, Molecule, mol);
5234 ival = NUM2INT(rb_Integer(val));
5235 if (ival < -mol->nangles || ival >= mol->nangles)
5236 rb_raise(rb_eMolbyError, "angle index (%d) out of range", ival);
5238 ival += mol->nangles;
5239 s_RebuildMDParameterIfNecessary(self, Qtrue);
5240 i1 = mol->angles[ival * 3];
5241 i2 = mol->angles[ival * 3 + 1];
5242 i3 = mol->angles[ival * 3 + 2];
5243 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5244 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5245 t3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
5246 ap = ParameterLookupAnglePar(mol->par, t1, t2, t3, i1, i2, i3, 0);
5249 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kAngleParType, ap - mol->par->anglePars);
5254 * dihedral_par(idx) -> ParameterRef
5256 * Returns the MD parameter for the idx-th dihedral.
5260 s_Molecule_DihedralPar(VALUE self, VALUE val)
5265 UInt t1, t2, t3, t4;
5267 Data_Get_Struct(self, Molecule, mol);
5268 ival = NUM2INT(rb_Integer(val));
5269 if (ival < -mol->ndihedrals || ival >= mol->ndihedrals)
5270 rb_raise(rb_eMolbyError, "dihedral index (%d) out of range", ival);
5272 ival += mol->ndihedrals;
5273 s_RebuildMDParameterIfNecessary(self, Qtrue);
5274 i1 = mol->dihedrals[ival * 4];
5275 i2 = mol->dihedrals[ival * 4 + 1];
5276 i3 = mol->dihedrals[ival * 4 + 2];
5277 i4 = mol->dihedrals[ival * 4 + 3];
5278 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5279 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5280 t3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
5281 t4 = ATOM_AT_INDEX(mol->atoms, i4)->type;
5282 tp = ParameterLookupDihedralPar(mol->par, t1, t2, t3, t4, i1, i2, i3, i4, 0);
5285 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kDihedralParType, tp - mol->par->dihedralPars);
5290 * improper_par(idx) -> ParameterRef
5292 * Returns the MD parameter for the idx-th improper.
5296 s_Molecule_ImproperPar(VALUE self, VALUE val)
5301 UInt t1, t2, t3, t4;
5303 Data_Get_Struct(self, Molecule, mol);
5304 ival = NUM2INT(rb_Integer(val));
5305 if (ival < -mol->nimpropers || ival >= mol->nimpropers)
5306 rb_raise(rb_eMolbyError, "improper index (%d) out of range", ival);
5308 ival += mol->nimpropers;
5309 s_RebuildMDParameterIfNecessary(self, Qtrue);
5310 i1 = mol->impropers[ival * 4];
5311 i2 = mol->impropers[ival * 4 + 1];
5312 i3 = mol->impropers[ival * 4 + 2];
5313 i4 = mol->impropers[ival * 4 + 3];
5314 t1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
5315 t2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
5316 t3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
5317 t4 = ATOM_AT_INDEX(mol->atoms, i4)->type;
5318 tp = ParameterLookupImproperPar(mol->par, t1, t2, t3, t4, i1, i2, i3, i4, 0);
5321 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kImproperParType, tp - mol->par->improperPars);
5326 * vdw_par(idx) -> ParameterRef
5328 * Returns the vdw parameter for the idx-th atom.
5332 s_Molecule_VdwPar(VALUE self, VALUE val)
5338 Data_Get_Struct(self, Molecule, mol);
5339 ival = NUM2INT(rb_Integer(val));
5340 if (ival < -mol->natoms || ival >= mol->natoms)
5341 rb_raise(rb_eMolbyError, "atom index (%d) out of range", ival);
5343 ival += mol->natoms;
5344 s_RebuildMDParameterIfNecessary(self, Qtrue);
5345 t1 = ATOM_AT_INDEX(mol->atoms, ival)->type;
5346 vp = ParameterLookupVdwPar(mol->par, t1, 0);
5349 return ValueFromMoleculeWithParameterTypeAndIndex(mol, kVdwParType, vp - mol->par->vdwPars);
5355 * start_step -> Integer
5357 * Returns the start step (defined by dcd format).
5360 s_Molecule_StartStep(VALUE self)
5363 Data_Get_Struct(self, Molecule, mol);
5364 return INT2NUM(mol->startStep);
5369 * start_step = Integer
5371 * Set the start step (defined by dcd format).
5374 s_Molecule_SetStartStep(VALUE self, VALUE val)
5377 Data_Get_Struct(self, Molecule, mol);
5378 mol->startStep = NUM2INT(rb_Integer(val));
5384 * steps_per_frame -> Integer
5386 * Returns the number of steps between frames (defined by dcd format).
5389 s_Molecule_StepsPerFrame(VALUE self)
5392 Data_Get_Struct(self, Molecule, mol);
5393 return INT2NUM(mol->stepsPerFrame);
5398 * steps_per_frame = Integer
5400 * Set the number of steps between frames (defined by dcd format).
5403 s_Molecule_SetStepsPerFrame(VALUE self, VALUE val)
5406 Data_Get_Struct(self, Molecule, mol);
5407 mol->stepsPerFrame = NUM2INT(rb_Integer(val));
5413 * ps_per_step -> Float
5415 * Returns the time increment (in picoseconds) for one step (defined by dcd format).
5418 s_Molecule_PsPerStep(VALUE self)
5421 Data_Get_Struct(self, Molecule, mol);
5422 return rb_float_new(mol->psPerStep);
5427 * ps_per_step = Float
5429 * Set the time increment (in picoseconds) for one step (defined by dcd format).
5432 s_Molecule_SetPsPerStep(VALUE self, VALUE val)
5435 Data_Get_Struct(self, Molecule, mol);
5436 mol->psPerStep = NUM2DBL(rb_Float(val));
5442 * find_angles -> Integer
5444 * Find the angles from the bonds. Returns the number of angles newly created.
5448 s_Molecule_FindAngles(VALUE self)
5454 Data_Get_Struct(self, Molecule, mol);
5455 if (mol == NULL || mol->natoms == 0)
5459 for (n1 = 0, ap = mol->atoms; n1 < mol->natoms; n1++, ap = ATOM_NEXT(ap)) {
5460 nc = ap->connect.count;
5462 for (i = 0; i < nc; i++) {
5463 n[0] = ap->connects[i];
5464 for (j = i + 1; j < nc; j++) {
5465 n[2] = ap->connects[j];
5466 if (MoleculeLookupAngle(mol, n[0], n[1], n[2]) < 0)
5467 AssignArray(&ip, &nip, sizeof(Int) * 3, nip, n);
5472 MolActionCreateAndPerform(mol, gMolActionAddAngles, nip * 3, ip, NULL);
5475 return INT2NUM(nip);
5480 * find_dihedrals -> Integer
5482 * Find the dihedrals from the bonds. Returns the number of dihedrals newly created.
5486 s_Molecule_FindDihedrals(VALUE self)
5490 int n1, i, j, k, nc1, nc2;
5492 Data_Get_Struct(self, Molecule, mol);
5493 if (mol == NULL || mol->natoms == 0)
5497 for (n1 = 0, ap1 = mol->atoms; n1 < mol->natoms; n1++, ap1 = ATOM_NEXT(ap1)) {
5498 nc1 = ap1->connect.count;
5500 for (i = 0; i < nc1; i++) {
5501 n[2] = ap1->connects[i];
5504 ap2 = ATOM_AT_INDEX(mol->atoms, n[2]);
5505 nc2 = ap2->connect.count;
5506 for (j = 0; j < nc1; j++) {
5507 n[0] = ap1->connects[j];
5510 for (k = 0; k < nc2; k++) {
5511 n[3] = ap2->connects[k];
5512 if (n[3] == n1 || n[3] == n[0])
5514 if (MoleculeLookupDihedral(mol, n[0], n[1], n[2], n[3]) < 0)
5515 AssignArray(&ip, &nip, sizeof(Int) * 4, nip, n);
5521 MolActionCreateAndPerform(mol, gMolActionAddDihedrals, nip * 4, ip, NULL);
5524 return INT2NUM(nip);
5530 * nresidues = Integer
5532 * Change the number of residues.
5535 s_Molecule_ChangeNresidues(VALUE self, VALUE val)
5538 int ival = NUM2INT(val);
5539 Data_Get_Struct(self, Molecule, mol);
5540 MolActionCreateAndPerform(mol, gMolActionChangeNumberOfResidues, ival);
5541 if (ival != mol->nresidues)
5542 rb_raise(rb_eMolbyError, "Cannot set the number of residues to %d (set to %d)", ival, mol->nresidues);
5548 * max_residue_number(atom_group = nil) -> Integer
5550 * Returns the maximum residue number actually used. If an atom group is given, only
5551 * these atoms are examined. If no atom is present, nil is returned.
5554 s_Molecule_MaxResSeq(int argc, VALUE *argv, VALUE self)
5560 Data_Get_Struct(self, Molecule, mol);
5561 rb_scan_args(argc, argv, "01", &gval);
5562 ig = (gval == Qnil ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
5563 maxSeq = MoleculeMaximumResidueNumber(mol, ig);
5564 return (maxSeq >= 0 ? INT2NUM(maxSeq) : Qnil);
5569 * min_residue_number(atom_group = nil) -> Integer
5571 * Returns the minimum residue number actually used. If an atom group is given, only
5572 * these atoms are examined. If no atom is present, nil is returned.
5575 s_Molecule_MinResSeq(int argc, VALUE *argv, VALUE self)
5581 Data_Get_Struct(self, Molecule, mol);
5582 rb_scan_args(argc, argv, "01", &gval);
5583 ig = (gval == Qnil ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
5584 minSeq = MoleculeMinimumResidueNumber(mol, ig);
5585 return (minSeq >= 0 ? INT2NUM(minSeq) : Qnil);
5590 * each_atom(atom_group = nil) {|aref| ...}
5592 * Execute the block, with the AtomRef object for each atom as the argument. If an atom
5593 * group is given, only these atoms are processed.
5594 * If atom_group is nil, this is equivalent to self.atoms.each, except that the return value
5595 * is self (a Molecule object).
5598 s_Molecule_EachAtom(int argc, VALUE *argv, VALUE self)
5606 Data_Get_Struct(self, Molecule, mol);
5607 rb_scan_args(argc, argv, "01", &gval);
5608 ig = (gval == Qnil ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
5609 arval = ValueFromMoleculeAndIndex(mol, 0);
5610 Data_Get_Struct(arval, AtomRef, aref);
5611 for (i = 0; i < mol->natoms; i++) {
5613 if (ig == NULL || IntGroupLookup(ig, i, NULL))
5617 IntGroupRelease(ig);
5623 * cell -> [a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]]
5625 * Returns the unit cell parameters. If cell is not set, returns nil.
5628 s_Molecule_Cell(VALUE self)
5633 Data_Get_Struct(self, Molecule, mol);
5634 if (mol->cell == NULL)
5636 val = rb_ary_new2(6);
5637 for (i = 0; i < 6; i++)
5638 rb_ary_push(val, rb_float_new(mol->cell->cell[i]));
5639 if (mol->cell->has_sigma) {
5640 for (i = 0; i < 6; i++) {
5641 rb_ary_push(val, rb_float_new(mol->cell->cellsigma[i]));
5649 * cell = [a, b, c, alpha, beta, gamma [, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]]
5650 * set_cell([a, b, c, alpha, beta, gamma[, sig_a, sig_b, sig_c, sig_alpha, sig_beta, sig_gamma]], convert_coord = nil)
5652 * Set the unit cell parameters. If the cell value is nil, then clear the current cell.
5653 If the given argument has 12 or more members, then the second half of the parameters represents the sigma values.
5654 This operation is undoable.
5655 Convert_coord is a flag to specify that the coordinates should be transformed so that the fractional coordinates remain the same.
5658 s_Molecule_SetCell(int argc, VALUE *argv, VALUE self)
5662 int i, convert_coord, n;
5664 Data_Get_Struct(self, Molecule, mol);
5665 rb_scan_args(argc, argv, "11", &val, &cval);
5670 val = rb_ary_to_ary(val);
5671 len = RARRAY_LEN(val);
5674 } else if (len >= 6) {
5676 } else rb_raise(rb_eMolbyError, "too few members for cell parameters (6 or 12 required)");
5677 for (i = 0; i < n; i++)
5678 d[i] = NUM2DBL(rb_Float((RARRAY_PTR(val))[i]));
5680 convert_coord = (RTEST(cval) ? 1 : 0);
5681 MolActionCreateAndPerform(mol, gMolActionSetCell, n, d, convert_coord);
5687 * box -> [avec, bvec, cvec, origin, flags]
5689 * Get the unit cell information in the form of a periodic bounding box.
5690 * Avec, bvec, cvec, origin are Vector3D objects, and flags is a 3-member array of
5691 * Integers which define whether the system is periodic along the axis.
5692 * If no unit cell is defined, nil is returned.
5695 s_Molecule_Box(VALUE self)
5699 Data_Get_Struct(self, Molecule, mol);
5700 if (mol == NULL || mol->cell == NULL)
5702 v[0] = ValueFromVector(&(mol->cell->axes[0]));
5703 v[1] = ValueFromVector(&(mol->cell->axes[1]));
5704 v[2] = ValueFromVector(&(mol->cell->axes[2]));
5705 v[3] = ValueFromVector(&(mol->cell->origin));
5706 v[4] = rb_ary_new3(3, INT2NUM(mol->cell->flags[0]), INT2NUM(mol->cell->flags[1]), INT2NUM(mol->cell->flags[2]));
5707 val = rb_ary_new4(5, v);
5713 * set_box(avec, bvec, cvec, origin = [0, 0, 0], flags = [1, 1, 1], convert_coordinates = nil)
5714 * set_box(d, origin = [0, 0, 0])
5717 * Set the unit cell parameters. Avec, bvec, and cvec can be either a Vector3D or a number.
5718 If it is a number, the x/y/z axis vector is multiplied with the given number and used
5720 Flags, if present, is a 3-member array of Integers defining whether the system is
5721 periodic along the axis.
5722 If convert_coordinates is true, then the coordinates are converted so that the fractional coordinates remain the same.
5723 In the second form, an isotropic box with cell-length d is set.
5724 In the third form, the existing box is cleared.
5725 Note: the sigma of the cell parameters is not cleared unless the periodic box itself is cleared.
5728 s_Molecule_SetBox(VALUE self, VALUE aval)
5732 static Vector ax[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
5734 Vector origin = {0, 0, 0};
5737 int i, convertCoordinates = 0;
5738 Data_Get_Struct(self, Molecule, mol);
5740 MolActionCreateAndPerform(mol, gMolActionClearBox);
5743 aval = rb_ary_to_ary(aval);
5744 for (i = 0; i < 6; i++) {
5745 if (i < RARRAY_LEN(aval))
5746 v[i] = (RARRAY_PTR(aval))[i];
5750 MolActionCreateAndPerform(mol, gMolActionClearBox);
5753 if ((v[1] == Qnil || v[2] == Qnil) && rb_obj_is_kind_of(v[0], rb_cNumeric)) {
5754 d = NUM2DBL(rb_Float(v[0]));
5755 for (i = 0; i < 3; i++)
5756 VecScale(vv[i], ax[i], d);
5758 VectorFromValue(v[1], &origin);
5759 flags[0] = flags[1] = flags[2] = 1;
5761 for (i = 0; i < 3; i++) {
5764 } else if (rb_obj_is_kind_of(v[i], rb_cNumeric)) {
5765 d = NUM2DBL(rb_Float(v[i]));
5766 VecScale(vv[i], ax[i], d);
5768 VectorFromValue(v[i], &vv[i]);
5770 flags[i] = (VecLength2(vv[i]) > 0.0);
5773 VectorFromValue(v[3], &origin);
5775 for (i = 0; i < 3; i++) {
5776 VALUE val = Ruby_ObjectAtIndex(v[4], i);
5777 flags[i] = (NUM2INT(rb_Integer(val)) != 0);
5781 convertCoordinates = 1;
5783 MolActionCreateAndPerform(mol, gMolActionSetBox, &(vv[0]), &(vv[1]), &(vv[2]), &origin, (flags[0] * 4 + flags[1] * 2 + flags[2]), convertCoordinates);
5789 * cell_periodicity -> [n1, n2, n3]
5791 * Get flags denoting whether the cell is periodic along the a/b/c axes. If the cell is not defined
5795 s_Molecule_CellPeriodicity(VALUE self)
5798 Data_Get_Struct(self, Molecule, mol);
5799 if (mol->cell == NULL)
5801 return rb_ary_new3(3, INT2FIX((int)mol->cell->flags[0]), INT2FIX((int)mol->cell->flags[1]), INT2FIX((int)mol->cell->flags[2]));
5806 * self.cell_periodicity = [n1, n2, n3] or Integer or nil
5807 * set_cell_periodicity = [n1, n2, n3] or Integer or nil
5809 * Set whether the cell is periodic along the a/b/c axes. If an integer is given as an argument,
5810 * its bits 2/1/0 (from the lowest) correspond to the a/b/c axes. Nil is equivalent to [0, 0, 0].
5811 * If cell is not defined, exception is raised.
5812 * This operation is undoable.
5815 s_Molecule_SetCellPeriodicity(VALUE self, VALUE arg)
5819 Data_Get_Struct(self, Molecule, mol);
5820 if (mol->cell == NULL)
5821 rb_raise(rb_eMolbyError, "periodic cell is not defined");
5824 else if (rb_obj_is_kind_of(arg, rb_cNumeric))
5825 flag = NUM2INT(rb_Integer(arg));
5829 arg = rb_ary_to_ary(arg);
5830 for (i = 0; i < 3 && i < RARRAY_LEN(arg); i++) {
5831 arg0 = RARRAY_PTR(arg)[i];
5832 if (arg0 != Qnil && arg0 != Qfalse && arg0 != INT2FIX(0))
5833 flag |= (1 << (2 - i));
5836 MolActionCreateAndPerform(mol, gMolActionSetCellPeriodicity, flag);
5842 * cell_flexibility -> bool
5844 * Returns the unit cell is flexible or not
5847 s_Molecule_CellFlexibility(VALUE self)
5849 rb_warn("cell_flexibility is obsolete (unit cell is always frame dependent)");
5852 Data_Get_Struct(self, Molecule, mol);
5853 if (mol->cell == NULL)
5855 if (mol->useFlexibleCell)
5857 else return Qfalse; */
5862 * self.cell_flexibility = bool
5863 * set_cell_flexibility(bool)
5865 * Change the unit cell is flexible or not
5868 s_Molecule_SetCellFlexibility(VALUE self, VALUE arg)
5870 rb_warn("set_cell_flexibility is obsolete (unit cell is always frame dependent)");
5873 Data_Get_Struct(self, Molecule, mol);
5874 MolActionCreateAndPerform(mol, gMolActionSetCellFlexibility, RTEST(arg) != 0);
5880 * cell_transform -> Transform
5882 * Get the transform matrix that converts internal coordinates to cartesian coordinates.
5883 * If cell is not defined, nil is returned.
5886 s_Molecule_CellTransform(VALUE self)
5889 Data_Get_Struct(self, Molecule, mol);
5890 if (mol == NULL || mol->cell == NULL)
5892 return ValueFromTransform(&(mol->cell->tr));
5897 * symmetry -> Array of Transforms
5898 * symmetries -> Array of Transforms
5900 * Get the currently defined symmetry operations. If no symmetry operation is defined,
5901 * returns an empty array.
5904 s_Molecule_Symmetry(VALUE self)
5909 Data_Get_Struct(self, Molecule, mol);
5910 if (mol->nsyms <= 0)
5911 return rb_ary_new();
5912 val = rb_ary_new2(mol->nsyms);
5913 for (i = 0; i < mol->nsyms; i++) {
5914 rb_ary_push(val, ValueFromTransform(&mol->syms[i]));
5921 * nsymmetries -> Integer
5923 * Get the number of currently defined symmetry operations.
5926 s_Molecule_Nsymmetries(VALUE self)
5929 Data_Get_Struct(self, Molecule, mol);
5930 return INT2NUM(mol->nsyms);
5935 * add_symmetry(Transform) -> Integer
5937 * Add a new symmetry operation. If no symmetry operation is defined and the
5938 * given argument is not an identity transform, then also add an identity
5939 * transform at the index 0.
5940 * Returns the total number of symmetries after operation.
5943 s_Molecule_AddSymmetry(VALUE self, VALUE trans)
5947 Data_Get_Struct(self, Molecule, mol);
5948 TransformFromValue(trans, &tr);
5949 MolActionCreateAndPerform(mol, gMolActionAddSymmetryOperation, &tr);
5950 return INT2NUM(mol->nsyms);
5955 * remove_symmetry(count = nil) -> Integer
5956 * remove_symmetries(count = nil) -> Integer
5958 * Remove the specified number of symmetry operations. The last added ones are removed
5959 * first. If count is nil, then all symmetry operations are removed. Returns the
5960 * number of leftover symmetries.
5963 s_Molecule_RemoveSymmetry(int argc, VALUE *argv, VALUE self)
5968 Data_Get_Struct(self, Molecule, mol);
5969 rb_scan_args(argc, argv, "01", &cval);
5973 n = NUM2INT(rb_Integer(cval));
5974 if (n < 0 || n > mol->nsyms)
5975 rb_raise(rb_eMolbyError, "the given count of symops is out of range");
5976 if (n == mol->nsyms)
5979 for (i = 0; i < n; i++)
5980 MolActionCreateAndPerform(mol, gMolActionDeleteSymmetryOperation);
5981 return INT2NUM(mol->nsyms);
5985 s_Molecule_AtomGroup_i(VALUE arg, VALUE values)
5987 Molecule *mol = (Molecule *)(((VALUE *)values)[0]);
5988 IntGroup *ig1 = (IntGroup *)(((VALUE *)values)[1]);
5989 int idx = s_Molecule_AtomIndexFromValue(mol, arg);
5990 IntGroup_RaiseIfError(IntGroupAdd(ig1, idx, 1));
5997 * atom_group {|aref| ...}
5998 * atom_group(arg1, arg2, ...)
5999 * atom_group(arg1, arg2, ...) {|aref| ...}
6001 * Specify a group of atoms. If no arguments are given, IntGroup\[0...natoms] is the result.
6002 * If arguments are given, then the atoms reprensented by the arguments are added to the
6003 * group. For a conversion of a string to an atom index, see the description
6004 * of Molecule#atom_index.
6005 * If a block is given, it is evaluated with an AtomRef (not atom index integers)
6006 * representing each atom, and the atoms are removed from the result if the block returns false.
6010 s_Molecule_AtomGroup(int argc, VALUE *argv, VALUE self)
6012 IntGroup *ig1, *ig2;
6014 Int i, startPt, interval;
6015 VALUE retval = IntGroup_Alloc(rb_cIntGroup);
6016 Data_Get_Struct(retval, IntGroup, ig1);
6017 Data_Get_Struct(self, Molecule, mol);
6019 IntGroup_RaiseIfError(IntGroupAdd(ig1, 0, mol->natoms));
6022 if (FIXNUM_P(*argv) || TYPE(*argv) == T_STRING) {
6023 i = s_Molecule_AtomIndexFromValue(mol, *argv);
6024 IntGroup_RaiseIfError(IntGroupAdd(ig1, i, 1));
6025 } else if (rb_obj_is_kind_of(*argv, rb_cIntGroup)) {
6026 ig2 = IntGroupFromValue(*argv);
6027 for (i = 0; (startPt = IntGroupGetStartPoint(ig2, i)) >= 0; i++) {
6028 interval = IntGroupGetInterval(ig2, i);
6029 IntGroup_RaiseIfError(IntGroupAdd(ig1, startPt, interval));
6031 IntGroupRelease(ig2);
6032 } else if (rb_respond_to(*argv, rb_intern("each"))) {
6034 values[0] = (VALUE)mol;
6035 values[1] = (VALUE)ig1;
6036 rb_iterate(rb_each, *argv, s_Molecule_AtomGroup_i, (VALUE)values);
6038 IntGroup_RaiseIfError(IntGroupAdd(ig1, NUM2INT(*argv), 1));
6043 if (rb_block_given_p()) {
6044 /* Evaluate the given block with an AtomRef as the argument, and delete
6045 the index if the block returns false */
6046 AtomRef *aref = AtomRefNew(mol, 0);
6047 VALUE arval = Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
6048 ig2 = IntGroupNew();
6049 IntGroupCopy(ig2, ig1);
6050 for (i = 0; (startPt = IntGroupGetNthPoint(ig2, i)) >= 0; i++) {
6052 if (startPt >= mol->natoms)
6054 aref->idx = startPt;
6055 resval = rb_yield(arval);
6057 IntGroupRemove(ig1, startPt, 1);
6059 IntGroupRelease(ig2);
6062 /* Remove points that are out of bounds */
6063 IntGroup_RaiseIfError(IntGroupRemove(ig1, mol->natoms, INT_MAX));
6070 * atom_index(val) -> Integer
6072 * Returns the atom index represented by val. val can be either a non-negative integer
6073 * (directly representing the atom index), a negative integer (representing <code>natoms - val</code>),
6074 * a string of type "resname.resid:name" or "resname:name" or "resid:name" or "name",
6075 * where resname, resid, name are the residue name, residue id, and atom name respectively.
6076 * If val is a string and multiple atoms match the description, the atom with the lowest index
6080 s_Molecule_AtomIndex(VALUE self, VALUE val)
6083 Data_Get_Struct(self, Molecule, mol);
6084 return INT2NUM(s_Molecule_AtomIndexFromValue(mol, val));
6089 * extract(group, dummy_flag = nil) -> Molecule
6091 * Extract the atoms given by group and return as a new molecule object.
6092 * If dummy_flag is true, then the atoms that are not included in the group but are connected
6093 * to any atoms in the group are converted to "dummy" atoms (i.e. with element "Du" and
6094 * names beginning with an underscore) and included in the new molecule object.
6097 s_Molecule_Extract(int argc, VALUE *argv, VALUE self)
6099 Molecule *mol1, *mol2;
6101 VALUE group, dummy_flag, retval;
6102 Data_Get_Struct(self, Molecule, mol1);
6103 rb_scan_args(argc, argv, "11", &group, &dummy_flag);
6104 ig = s_Molecule_AtomGroupFromValue(self, group);
6105 if (MoleculeExtract(mol1, &mol2, ig, (dummy_flag != Qnil && dummy_flag != Qfalse)) != 0) {
6108 retval = ValueFromMolecule(mol2);
6110 IntGroupRelease(ig);
6116 * add(molecule2) -> self
6118 * Combine two molecules. The residue numbers of the newly added atoms may be renumbered to avoid
6120 This operation is undoable.
6123 s_Molecule_Add(VALUE self, VALUE val)
6125 Molecule *mol1, *mol2;
6126 Data_Get_Struct(self, Molecule, mol1);
6127 mol2 = MoleculeFromValue(val);
6128 MolActionCreateAndPerform(mol1, gMolActionMergeMolecule, mol2, NULL);
6134 * remove(group) -> Molecule
6136 * The atoms designated by the given group are removed from the molecule.
6137 * This operation is undoable.
6140 s_Molecule_Remove(VALUE self, VALUE group)
6145 IntGroupIterator iter;
6147 Data_Get_Struct(self, Molecule, mol1);
6148 group = rb_funcall(self, rb_intern("atom_group"), 1, group);
6149 if (!rb_obj_is_kind_of(group, rb_cIntGroup))
6150 rb_raise(rb_eMolbyError, "IntGroup instance is expected");
6151 Data_Get_Struct(group, IntGroup, ig);
6153 /* Remove the bonds between the two fragments */
6154 /* (This is necessary for undo to work correctly) */
6155 IntGroupIteratorInit(ig, &iter);
6157 while ((i = IntGroupIteratorNext(&iter)) >= 0) {
6158 Atom *ap = ATOM_AT_INDEX(mol1->atoms, i);
6160 cp = AtomConnectData(&ap->connect);
6161 for (j = 0; j < ap->connect.count; j++) {
6163 if (!IntGroupLookup(ig, n, NULL)) {
6164 /* bond i-n, i is in ig and n is not */
6165 int k = MoleculeLookupBond(mol1, i, n);
6169 IntGroupAdd(bg, k, 1);
6174 IntGroupIteratorRelease(&iter);
6177 MolActionCreateAndPerform(mol1, gMolActionDeleteBonds, bg);
6178 IntGroupRelease(bg);
6181 if (MolActionCreateAndPerform(mol1, gMolActionUnmergeMolecule, ig) == 0)
6188 * create_atom(name, pos = -1) -> AtomRef
6190 * Create a new atom with the specified name (may contain residue
6191 * information) and position (if position is out of range, the atom is appended at
6192 * the end). Returns the reference to the new atom.
6193 * This operation is undoable.
6196 s_Molecule_CreateAnAtom(int argc, VALUE *argv, VALUE self)
6203 char *p, resName[6], atomName[6];
6205 Data_Get_Struct(self, Molecule, mol);
6206 rb_scan_args(argc, argv, "02", &name, &ival);
6208 pos = NUM2INT(rb_Integer(ival));
6211 p = StringValuePtr(name);
6213 i = MoleculeAnalyzeAtomName(p, resName, &resSeq, atomName);
6214 if (atomName[0] == 0)
6215 rb_raise(rb_eMolbyError, "bad atom name specification: %s", p);
6218 if (p == NULL || p[0] == 0) {
6219 memset(atomName, 0, 4);
6222 memset(&arec, 0, sizeof(arec));
6223 strncpy(arec.aname, atomName, 4);
6225 strncpy(arec.resName, resName, 4);
6226 arec.resSeq = resSeq;
6228 arec.occupancy = 1.0;
6229 // i = MoleculeCreateAnAtom(mol, &arec);
6230 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &arec, pos, &pos) != 0)
6232 aref = AtomRefNew(mol, pos);
6233 return Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
6238 * duplicate_atom(atomref, pos = -1) -> AtomRef
6240 * Create a new atom with the same attributes (but no bonding information)
6241 * with the specified atom. Returns the reference to the new atom.
6242 * This operation is undoable.
6245 s_Molecule_DuplicateAnAtom(int argc, VALUE *argv, VALUE self)
6251 VALUE retval, aval, ival;
6253 Data_Get_Struct(self, Molecule, mol);
6254 rb_scan_args(argc, argv, "11", &aval, &ival);
6255 if (FIXNUM_P(aval)) {
6256 int idx = NUM2INT(aval);
6257 if (idx < 0 || idx >= mol->natoms)
6258 rb_raise(rb_eMolbyError, "atom index out of range: %d", idx);
6259 apsrc = ATOM_AT_INDEX(mol->atoms, idx);
6261 apsrc = s_AtomFromValue(aval);
6264 rb_raise(rb_eMolbyError, "bad atom specification");
6266 pos = NUM2INT(rb_Integer(ival));
6268 AtomDuplicate(&arec, apsrc);
6269 arec.connect.count = 0;
6270 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &arec, pos, &pos) != 0)
6273 aref = AtomRefNew(mol, pos);
6274 retval = Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
6282 * create_bond(n1, n2, ...) -> Integer
6284 * Create bonds between atoms n1 and n2, n3 and n4, and so on. If the corresponding bond is already present for a particular pair,
6285 * do nothing for that pair. Returns the number of bonds actually created.
6286 * This operation is undoable.
6289 s_Molecule_CreateBond(int argc, VALUE *argv, VALUE self)
6292 Int i, j, *ip, old_nbonds;
6294 rb_raise(rb_eMolbyError, "missing arguments");
6296 rb_raise(rb_eMolbyError, "bonds should be specified by pairs of atom indices");
6297 Data_Get_Struct(self, Molecule, mol);
6298 ip = ALLOC_N(Int, argc + 1);
6299 for (i = j = 0; i < argc; i++, j++) {
6300 ip[j] = s_Molecule_AtomIndexFromValue(mol, argv[i]);
6302 if (MoleculeLookupBond(mol, ip[j - 1], ip[j]) >= 0)
6303 j -= 2; /* This bond is already present: skip it */
6306 old_nbonds = mol->nbonds;
6308 ip[j] = kInvalidIndex;
6309 i = MolActionCreateAndPerform(mol, gMolActionAddBonds, j, ip, NULL);
6313 rb_raise(rb_eMolbyError, "atom index out of range");
6315 rb_raise(rb_eMolbyError, "too many bonds");
6317 rb_raise(rb_eMolbyError, "duplicate bonds");
6319 rb_raise(rb_eMolbyError, "cannot create bond to itself");
6321 rb_raise(rb_eMolbyError, "error in creating bonds");
6322 return INT2NUM(mol->nbonds - old_nbonds);
6327 * molecule.remove_bonds(n1, n2, ...) -> Integer
6329 * Remove bonds between atoms n1 and n2, n3 and n4, and so on. If the corresponding bond is not present for
6330 * a particular pair, do nothing for that pair. Returns the number of bonds actually removed.
6331 * This operation is undoable.
6334 s_Molecule_RemoveBond(int argc, VALUE *argv, VALUE self)
6340 rb_raise(rb_eMolbyError, "missing arguments");
6342 rb_raise(rb_eMolbyError, "bonds should be specified by pairs of atom indices");
6343 Data_Get_Struct(self, Molecule, mol);
6345 for (i = j = 0; i < argc; i++, j = 1 - j) {
6346 n[j] = s_Molecule_AtomIndexFromValue(mol, argv[i]);
6348 Int k = MoleculeLookupBond(mol, n[0], n[1]);
6352 IntGroupAdd(bg, k, 1);
6357 MolActionCreateAndPerform(mol, gMolActionDeleteBonds, bg);
6358 i = IntGroupGetCount(bg);
6359 IntGroupRelease(bg);
6366 * add_angle(n1, n2, n3) -> Molecule
6368 * Add angle n1-n2-n3. Returns self. Usually, angles are automatically added
6369 * when a bond is created, so it is rarely necessary to use this method explicitly.
6370 * This operation is undoable.
6373 s_Molecule_AddAngle(VALUE self, VALUE v1, VALUE v2, VALUE v3)
6377 Data_Get_Struct(self, Molecule, mol);
6378 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6379 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6380 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6381 if (MoleculeLookupAngle(mol, n[0], n[1], n[2]) >= 0)
6382 rb_raise(rb_eMolbyError, "angle %d-%d-%d is already present", n[0], n[1], n[2]);
6383 n[3] = kInvalidIndex;
6384 MolActionCreateAndPerform(mol, gMolActionAddAngles, 3, n, NULL);
6390 * remove_angle(n1, n2, n3) -> Molecule
6392 * Remove angle n1-n2-n3. Returns self. Usually, angles are automatically removed
6393 * when a bond is removed, so it is rarely necessary to use this method explicitly.
6394 * This operation is undoable.
6397 s_Molecule_RemoveAngle(VALUE self, VALUE v1, VALUE v2, VALUE v3)
6402 Data_Get_Struct(self, Molecule, mol);
6403 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6404 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6405 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6406 if ((n[3] = MoleculeLookupAngle(mol, n[0], n[1], n[2])) < 0)
6407 rb_raise(rb_eMolbyError, "angle %d-%d-%d is not present", n[0], n[1], n[2]);
6408 ig = IntGroupNewWithPoints(n[3], 1, -1);
6409 MolActionCreateAndPerform(mol, gMolActionDeleteAngles, ig);
6410 IntGroupRelease(ig);
6416 * add_dihedral(n1, n2, n3, n4) -> Molecule
6418 * Add dihedral n1-n2-n3-n4. Returns self. Usually, dihedrals are automatically added
6419 * when a bond is created, so it is rarely necessary to use this method explicitly.
6420 * This operation is undoable.
6423 s_Molecule_AddDihedral(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6427 Data_Get_Struct(self, Molecule, mol);
6428 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6429 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6430 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6431 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6432 if (MoleculeLookupDihedral(mol, n[0], n[1], n[2], n[3]) >= 0)
6433 rb_raise(rb_eMolbyError, "dihedral %d-%d-%d-%d is already present", n[0], n[1], n[2], n[3]);
6434 n[4] = kInvalidIndex;
6435 MolActionCreateAndPerform(mol, gMolActionAddDihedrals, 4, n, NULL);
6441 * remove_dihedral(n1, n2, n3, n4) -> Molecule
6443 * Remove dihedral n1-n2-n3-n4. Returns self. Usually, dihedrals are automatically removed
6444 * when a bond is removed, so it is rarely necessary to use this method explicitly.
6445 * This operation is undoable.
6448 s_Molecule_RemoveDihedral(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6453 Data_Get_Struct(self, Molecule, mol);
6454 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6455 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6456 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6457 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6458 if ((n[4] = MoleculeLookupDihedral(mol, n[0], n[1], n[2], n[3])) < 0)
6459 rb_raise(rb_eMolbyError, "dihedral %d-%d-%d-%d is not present", n[0], n[1], n[2], n[3]);
6460 ig = IntGroupNewWithPoints(n[4], 1, -1);
6461 MolActionCreateAndPerform(mol, gMolActionDeleteDihedrals, ig);
6462 IntGroupRelease(ig);
6468 * add_improper(n1, n2, n3, n4) -> Molecule
6470 * Add dihedral n1-n2-n3-n4. Returns self. Unlike angles and dihedrals, impropers are
6471 * not automatically added when a new bond is created, so this method is more useful than
6472 * the angle/dihedral counterpart.
6473 * This operation is undoable.
6476 s_Molecule_AddImproper(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
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 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6485 if (MoleculeLookupImproper(mol, n[0], n[1], n[2], n[3]) >= 0)
6486 rb_raise(rb_eMolbyError, "improper %d-%d-%d-%d is already present", n[0], n[1], n[2], n[3]);
6487 n[4] = kInvalidIndex;
6488 MolActionCreateAndPerform(mol, gMolActionAddImpropers, 4, n, NULL);
6494 * remove_improper(n1, n2, n3, n4) -> Molecule
6496 * Remove improper n1-n2-n3-n4. Returns self. Unlike angles and dihedrals, impropers are
6497 * not automatically added when a new bond is created, so this method is more useful than
6498 * the angle/dihedral counterpart.
6499 * This operation is undoable.
6502 s_Molecule_RemoveImproper(VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4)
6507 Data_Get_Struct(self, Molecule, mol);
6508 n[0] = s_Molecule_AtomIndexFromValue(mol, v1);
6509 n[1] = s_Molecule_AtomIndexFromValue(mol, v2);
6510 n[2] = s_Molecule_AtomIndexFromValue(mol, v3);
6511 n[3] = s_Molecule_AtomIndexFromValue(mol, v4);
6512 if ((n[4] = MoleculeLookupImproper(mol, n[0], n[1], n[2], n[3])) < 0)
6513 rb_raise(rb_eMolbyError, "improper %d-%d-%d-%d is not present", n[0], n[1], n[2], n[3]);
6514 ig = IntGroupNewWithPoints(n[4], 1, -1);
6515 MolActionCreateAndPerform(mol, gMolActionDeleteImpropers, ig);
6516 IntGroupRelease(ig);
6522 * assign_residue(group, res) -> Molecule
6524 * Assign the specified atoms as the given residue. res can either be an integer, "resname"
6525 * or "resname.resno". When the residue number is not specified, the residue number of
6526 * the first atom in the group is used.
6527 * This operation is undoable.
6530 s_Molecule_AssignResidue(VALUE self, VALUE range, VALUE res)
6534 char *p, *pp, buf[16];
6537 Data_Get_Struct(self, Molecule, mol);
6539 /* Parse the argument res */
6540 if (FIXNUM_P(res)) {
6541 /* We can assume Fixnum here because Bignum is non-realistic as residue numbers */
6542 resid = NUM2INT(res);
6545 p = StringValuePtr(res);
6546 pp = strchr(p, '.');
6548 resid = atoi(pp + 1);
6554 if (n > sizeof buf - 1)
6559 ig = s_Molecule_AtomGroupFromValue(self, range);
6560 if (ig == NULL || IntGroupGetCount(ig) == 0)
6564 /* Use the residue number of the first specified atom */
6565 n = IntGroupGetNthPoint(ig, 0);
6566 if (n >= mol->natoms)
6567 rb_raise(rb_eMolbyError, "Atom index (%d) out of range", n);
6568 ap = ATOM_AT_INDEX(mol->atoms, n);
6571 /* Change the residue number */
6572 MolActionCreateAndPerform(mol, gMolActionChangeResidueNumber, ig, resid);
6573 /* Change the residue name if necessary */
6577 seqs[1] = kInvalidIndex; */
6578 MolActionCreateAndPerform(mol, gMolActionChangeResidueNames, 1, &resid, 4, buf);
6580 IntGroupRelease(ig);
6586 * offset_residue(group, offset) -> Molecule
6588 * Offset the residue number of the specified atoms. If any of the residue number gets
6589 * negative, then exception is thrown.
6590 * This operation is undoable.
6593 s_Molecule_OffsetResidue(VALUE self, VALUE range, VALUE offset)
6598 Data_Get_Struct(self, Molecule, mol);
6599 ig = s_Molecule_AtomGroupFromValue(self, range);
6600 ofs = NUM2INT(offset);
6601 result = MolActionCreateAndPerform(mol, gMolActionOffsetResidueNumbers, ig, ofs, -1);
6603 rb_raise(rb_eMolbyError, "residue number of atom %d becomes negative", result - 1);
6604 IntGroupRelease(ig);
6610 * renumber_atoms(array) -> IntGroup
6612 * Change the order of atoms so that the atoms specified in the array argument appear
6613 * in this order from the top of the molecule. The atoms that are not included in array
6614 * are placed after these atoms, and these atoms are returned as an intGroup.
6615 * This operation is undoable.
6618 s_Molecule_RenumberAtoms(VALUE self, VALUE array)
6624 VALUE *valp, retval;
6625 Data_Get_Struct(self, Molecule, mol);
6626 if (TYPE(array) != T_ARRAY)
6627 array = rb_funcall(array, rb_intern("to_a"), 0);
6628 n = RARRAY_LEN(array);
6629 valp = RARRAY_PTR(array);
6630 new2old = ALLOC_N(Int, n + 1);
6631 for (i = 0; i < n; i++)
6632 new2old[i] = s_Molecule_AtomIndexFromValue(mol, valp[i]);
6633 new2old[i] = kInvalidIndex;
6634 i = MolActionCreateAndPerform(mol, gMolActionRenumberAtoms, i, new2old);
6636 rb_raise(rb_eMolbyError, "Atom index out of range");
6638 rb_raise(rb_eMolbyError, "Duplicate entry");
6640 rb_raise(rb_eMolbyError, "Internal inconsistency during atom renumbering");
6641 retval = IntGroup_Alloc(rb_cIntGroup);
6642 Data_Get_Struct(retval, IntGroup, ig);
6643 if (mol->natoms > n)
6644 IntGroup_RaiseIfError(IntGroupAdd(ig, n, mol->natoms - n));
6651 * find_close_atoms(atom, limit = 1.2) -> array of Integers (atom indices)
6653 * Find atoms that are within the threshold distance from the given atom.
6654 * If limit is a positive number, the threshold distance is the sum of the vdw radii times limit.
6655 * If limit is a negative number, its absolute value is used for the threshold distance in angstrom.
6656 * If limit is not given, a default value of 1.2 is used.
6657 * An array of atom indices is returned. If no atoms are found, an empty array is returned.
6660 s_Molecule_FindCloseAtoms(int argc, VALUE *argv, VALUE self)
6665 Int n1, nbonds, *bonds;
6666 Data_Get_Struct(self, Molecule, mol);
6667 rb_scan_args(argc, argv, "11", &aval, &limval);
6668 n1 = s_Molecule_AtomIndexFromValue(mol, aval);
6672 limit = NUM2DBL(rb_Float(limval));
6673 nbonds = 0; /* This initialization is necessary: see comments in MoleculeFindCloseAtoms() */
6675 MoleculeFindCloseAtoms(mol, n1, limit, &nbonds, &bonds, 0);
6676 aval = rb_ary_new();
6678 for (n1 = 0; n1 < nbonds; n1++)
6679 rb_ary_push(aval, INT2NUM(bonds[n1 * 2 + 1]));
6687 * guess_bonds(limit = 1.2) -> Integer
6689 * Create bonds between atoms that are within the threshold distance.
6690 * If limit is a positive number, the threshold distance is the sum of the vdw radii times limit.
6691 * If limit is a negative number, its absolute value is used for the threshold distance in angstrom.
6692 * If limit is not given, a default value of 1.2 is used.
6693 * The number of the newly created bonds is returned.
6694 * This operation is undoable.
6697 s_Molecule_GuessBonds(int argc, VALUE *argv, VALUE self)
6703 Data_Get_Struct(self, Molecule, mol);
6704 rb_scan_args(argc, argv, "01", &limval);
6708 limit = NUM2DBL(rb_Float(limval));
6709 MoleculeGuessBonds(mol, limit, &nbonds, &bonds);
6711 MolActionCreateAndPerform(mol, gMolActionAddBonds, nbonds * 2, bonds, NULL);
6714 return INT2NUM(nbonds);
6719 * register_undo(script, *args)
6721 * Register an undo operation with the current molecule.
6724 s_Molecule_RegisterUndo(int argc, VALUE *argv, VALUE self)
6729 Data_Get_Struct(self, Molecule, mol);
6730 rb_scan_args(argc, argv, "1*", &script, &args);
6731 act = MolActionNew(SCRIPT_ACTION("R"), StringValuePtr(script), args);
6732 MolActionCallback_registerUndo(mol, act);
6738 * undo_enabled? -> bool
6740 * Returns true if undo is enabled for this molecule; otherwise no.
6743 s_Molecule_UndoEnabled(VALUE self)
6746 Data_Get_Struct(self, Molecule, mol);
6747 if (MolActionCallback_isUndoRegistrationEnabled(mol))
6754 * undo_enabled = bool
6756 * Enable or disable undo.
6759 s_Molecule_SetUndoEnabled(VALUE self, VALUE val)
6762 Data_Get_Struct(self, Molecule, mol);
6763 MolActionCallback_setUndoRegistrationEnabled(mol, (val != Qfalse && val != Qnil));
6769 * selection -> IntGroup
6771 * Returns the current selection.
6774 s_Molecule_Selection(VALUE self)
6779 Data_Get_Struct(self, Molecule, mol);
6780 if (mol != NULL && (ig = MoleculeGetSelection(mol)) != NULL) {
6781 ig = IntGroupNewFromIntGroup(ig); /* Duplicate, so that the change from GUI does not affect the value */
6782 val = ValueFromIntGroup(ig);
6783 IntGroupRelease(ig);
6785 val = IntGroup_Alloc(rb_cIntGroup);
6791 s_Molecule_SetSelectionSub(VALUE self, VALUE val, int undoable)
6795 Data_Get_Struct(self, Molecule, mol);
6799 ig = s_Molecule_AtomGroupFromValue(self, val);
6801 MolActionCreateAndPerform(mol, gMolActionSetSelection, ig);
6803 MoleculeSetSelection(mol, ig);
6805 IntGroupRelease(ig);
6811 * selection = IntGroup
6813 * Set the current selection. The right-hand operand may be nil.
6814 * This operation is _not_ undoable. If you need undo, use set_undoable_selection instead.
6817 s_Molecule_SetSelection(VALUE self, VALUE val)
6819 return s_Molecule_SetSelectionSub(self, val, 0);
6824 * set_undoable_selection(IntGroup)
6826 * Set the current selection with undo registration. The right-hand operand may be nil.
6827 * This operation is undoable.
6830 s_Molecule_SetUndoableSelection(VALUE self, VALUE val)
6832 return s_Molecule_SetSelectionSub(self, val, 1);
6837 * hidden_atoms -> IntGroup
6839 * Returns the currently hidden atoms.
6842 s_Molecule_HiddenAtoms(VALUE self)
6844 rb_raise(rb_eMolbyError, "set_hidden_atoms is now obsolete. Try using Molecule#is_atom_visible or AtomRef#hidden.");
6845 return Qnil; /* Not reached */
6849 Data_Get_Struct(self, Molecule, mol);
6854 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
6855 if (ap->exflags & kAtomHiddenFlag)
6856 IntGroupAdd(ig, i, 1);
6858 val = ValueFromIntGroup(ig);
6859 IntGroupRelease(ig);
6862 } else return Qnil; */
6867 * set_hidden_atoms(IntGroup)
6868 * self.hidden_atoms = IntGroup
6870 * Hide the specified atoms. This operation is _not_ undoable.
6873 s_Molecule_SetHiddenAtoms(VALUE self, VALUE val)
6875 rb_raise(rb_eMolbyError, "set_hidden_atoms is now obsolete. Try using Molecule#is_atom_visible or AtomRef#hidden.");
6876 return Qnil; /* Not reached */
6879 Data_Get_Struct(self, Molecule, mol);
6887 ig = s_Molecule_AtomGroupFromValue(self, val);
6888 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
6889 if (ig != NULL && IntGroupLookup(ig, i, NULL)) {
6890 ap->exflags |= kAtomHiddenFlag;
6892 ap->exflags &= kAtomHiddenFlag;
6896 IntGroupRelease(ig);
6897 MoleculeCallback_notifyModification(mol, 0);
6904 * select_frame(index)
6907 * Select the specified frame. If successful, returns true, otherwise returns false.
6910 s_Molecule_SelectFrame(VALUE self, VALUE val)
6913 int ival = NUM2INT(val);
6914 Data_Get_Struct(self, Molecule, mol);
6915 ival = MoleculeSelectFrame(mol, ival, 1);
6925 * Get the current frame.
6928 s_Molecule_Frame(VALUE self)
6931 Data_Get_Struct(self, Molecule, mol);
6932 return INT2NUM(mol->cframe);
6937 * nframes -> Integer
6939 * Get the number of frames.
6942 s_Molecule_Nframes(VALUE self)
6945 Data_Get_Struct(self, Molecule, mol);
6946 return INT2NUM(MoleculeGetNumberOfFrames(mol));
6951 * insert_frame(integer, coordinates = nil, cell_axes = nil) -> bool
6952 * insert_frames(intGroup = nil, coordinates = nil, cell_axes = nil) -> bool
6954 * Insert new frames at the indices specified by the intGroup. If the first argument is
6955 * an integer, a single new frame is inserted at that index. If the first argument is
6956 * nil, a new frame is inserted at the last. If non-nil coordinates is given, it
6957 * should be an array of arrays of Vector3Ds, then those coordinates are set
6958 * to the new frame. Otherwise, the coordinates of current molecule are copied
6960 * Returns an intGroup representing the inserted frames if successful, nil if not.
6963 s_Molecule_InsertFrames(int argc, VALUE *argv, VALUE self)
6965 VALUE val, coords, cells;
6968 int count, ival, i, j, len, len_c, len2, nframes;
6971 Data_Get_Struct(self, Molecule, mol);
6972 rb_scan_args(argc, argv, "12", &val, &coords, &cells);
6973 if (coords != Qnil) {
6974 if (TYPE(coords) != T_ARRAY)
6975 rb_raise(rb_eTypeError, "the coordinates should be given as an array of Vector3D");
6976 len = RARRAY_LEN(coords);
6978 if (cells != Qnil) {
6979 if (mol->cell == NULL)
6980 rb_raise(rb_eTypeError, "the unit cell is not defined but the cell axes are given");
6981 if (TYPE(cells) != T_ARRAY)
6982 rb_raise(rb_eTypeError, "the cell axes should be given as an array of Vector3D");
6983 len_c = RARRAY_LEN(cells);
6985 count = (len > len_c ? len : len_c); /* May be zero; will be updated later */
6986 nframes = MoleculeGetNumberOfFrames(mol);
6988 ig = IntGroupNewWithPoints(nframes, (count > 0 ? count : 1), -1);
6989 val = ValueFromIntGroup(ig);
6991 ig = IntGroupFromValue(val);
6993 count = IntGroupGetCount(ig); /* Count is updated here */
6994 vp = ALLOC_N(Vector, mol->natoms * count);
6996 vp2 = ALLOC_N(Vector, 4 * count);
7000 rb_raise(rb_eMolbyError, "the coordinates should contain no less than %d arrays (for frames)", count);
7001 ptr = RARRAY_PTR(coords);
7002 for (i = 0; i < count; i++) {
7003 if (TYPE(ptr[i]) != T_ARRAY)
7004 rb_raise(rb_eTypeError, "the coordinate array contains non-array object at index %d", i);
7005 len2 = RARRAY_LEN(ptr[i]);
7006 if (len2 < mol->natoms)
7007 rb_raise(rb_eMolbyError, "the array at index %d contains less than %d elements", i, mol->natoms);
7008 ptr2 = RARRAY_PTR(ptr[i]);
7009 for (j = 0; j < mol->natoms; j++)
7010 VectorFromValue(ptr2[j], &vp[i * mol->natoms + j]);
7014 for (i = 0; i < count; i++) {
7015 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
7016 vp[i * mol->natoms + j] = ap->r;
7022 rb_raise(rb_eMolbyError, "the cell vectors should contain no less than %d arrays (for frames)", count);
7023 ptr = RARRAY_PTR(cells);
7024 for (i = 0; i < count; i++) {
7025 if (TYPE(ptr[i]) != T_ARRAY)
7026 rb_raise(rb_eTypeError, "the cell parameter array contains non-array object at index %d", i);
7027 len2 = RARRAY_LEN(ptr[i]);
7029 rb_raise(rb_eMolbyError, "the cell parameter should contain 4 vectors");
7030 ptr2 = RARRAY_PTR(ptr[i]);
7031 for (j = 0; j < 4; j++)
7032 VectorFromValue(ptr2[j], &vp2[i * 4 + j]);
7035 ival = MolActionCreateAndPerform(mol, gMolActionInsertFrames, ig, mol->natoms * count, vp, (vp2 != NULL ? 4 * count : 0), vp2);
7036 IntGroupRelease(ig);
7040 return (ival >= 0 ? val : Qnil);
7045 * create_frame(coordinates = nil) -> Integer
7046 * create_frames(coordinates = nil) -> Integer
7048 * Same as molecule.insert_frames(nil, coordinates).
7051 s_Molecule_CreateFrames(int argc, VALUE *argv, VALUE self)
7054 rb_scan_args(argc, argv, "02", &vals[1], &vals[2]);
7056 return s_Molecule_InsertFrames(3, vals, self);
7061 * remove_frames(IntGroup, wantCoordinates = false)
7063 * Remove the frames at group. If wantsCoordinates is false (default), returns true if successful
7064 * and nil otherwise. If wantsCoordinates is true, an array of arrays of the coordinates in the
7065 * removed frames is returned if operation is successful.
7068 s_Molecule_RemoveFrames(int argc, VALUE *argv, VALUE self)
7075 Data_Get_Struct(self, Molecule, mol);
7076 rb_scan_args(argc, argv, "11", &val, &flag);
7077 ig = IntGroupFromValue(val);
7078 count = IntGroupGetCount(ig);
7080 /* Create return value before removing frames */
7085 retval = rb_ary_new2(count);
7086 for (i = 0; i < count; i++) {
7087 n = IntGroupGetNthPoint(ig, i);
7088 coords = rb_ary_new2(mol->natoms);
7089 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
7090 if (n < ap->nframes && n != mol->cframe)
7093 rb_ary_push(coords, ValueFromVector(&v));
7095 rb_ary_push(retval, coords);
7097 } else retval = Qtrue;
7098 if (MolActionCreateAndPerform(mol, gMolActionRemoveFrames, ig) >= 0)
7105 * each_frame {|n| ...}
7107 * Set the frame number from 0 to nframes-1 and execute the block. The block argument is
7108 * the frame number. After completion, the original frame number is restored.
7111 s_Molecule_EachFrame(VALUE self)
7113 int i, cframe, nframes;
7115 Data_Get_Struct(self, Molecule, mol);
7116 cframe = mol->cframe;
7117 nframes = MoleculeGetNumberOfFrames(mol);
7119 for (i = 0; i < nframes; i++) {
7120 MoleculeSelectFrame(mol, i, 1);
7121 rb_yield(INT2NUM(i));
7123 MoleculeSelectFrame(mol, cframe, 1);
7130 * set_atom_attr(index, key, value)
7132 * Set the atom attribute for the specified atom.
7133 * This operation is undoable.
7136 s_Molecule_SetAtomAttr(VALUE self, VALUE idx, VALUE key, VALUE val)
7140 Data_Get_Struct(self, Molecule, mol);
7141 aref = ValueFromMoleculeAndIndex(mol, s_Molecule_AtomIndexFromValue(mol, idx));
7142 oldval = s_AtomRef_GetAttr(aref, key);
7145 s_AtomRef_SetAttr(aref, key, val);
7151 * get_atom_attr(index, key)
7153 * Get the atom attribute for the specified atom.
7156 s_Molecule_GetAtomAttr(VALUE self, VALUE idx, VALUE key)
7158 return s_Molecule_SetAtomAttr(self, idx, key, Qundef);
7163 * get_coord_from_frame(index, group = nil)
7165 * Copy the coordinates from the indicated frame. If group is specified, only the specified atoms
7166 * are modified. Third argument (cflag) is now obsolete (it used to specify whether the cell parameters are to be
7167 * copied; now they are always copied)
7170 s_Molecule_GetCoordFromFrame(int argc, VALUE *argv, VALUE self)
7173 VALUE ival, gval, cval;
7174 Int index, i, j, n, nn;
7176 IntGroupIterator iter;
7179 Data_Get_Struct(self, Molecule, mol);
7180 rb_scan_args(argc, argv, "12", &ival, &gval, &cval);
7182 rb_warn("The 3rd argument to get_coord_from_frame() is now obsolete");
7183 index = NUM2INT(rb_Integer(ival));
7184 if (index < 0 || index >= (n = MoleculeGetNumberOfFrames(mol))) {
7186 rb_raise(rb_eMolbyError, "No frame is present");
7188 rb_raise(rb_eMolbyError, "Frame index (%d) out of range (should be 0..%d)", index, n - 1);
7191 ig = IntGroupNewWithPoints(0, mol->natoms, -1);
7193 ig = s_Molecule_AtomGroupFromValue(self, gval);
7195 n = IntGroupGetCount(ig);
7197 vp = (Vector *)calloc(sizeof(Vector), n);
7198 IntGroupIteratorInit(ig, &iter);
7201 while ((i = IntGroupIteratorNext(&iter)) >= 0) {
7202 ap = ATOM_AT_INDEX(mol->atoms, i);
7203 if (index < ap->nframes) {
7204 vp[j] = ap->frames[index];
7212 MolActionCreateAndPerform(mol, gMolActionSetAtomPositions, ig, n, vp);
7214 if (mol->cell != NULL && mol->frame_cells != NULL && index < mol->nframe_cells) {
7215 vp = mol->frame_cells + index * 4;
7216 MolActionCreateAndPerform(mol, gMolActionSetBox, vp, vp + 1, vp + 2, vp + 3, -1, 0);
7218 IntGroupIteratorRelease(&iter);
7220 IntGroupRelease(ig);
7226 * fragment(n1, *exatoms) -> IntGroup
7227 * fragment(group, *exatoms) -> IntGroup
7229 * Get the fragment including the atom n1 or the atom group. If additional arguments are given,
7230 * those atoms will not be counted during the search.
7233 s_Molecule_Fragment(int argc, VALUE *argv, VALUE self)
7236 IntGroup *baseg, *ig, *exatoms;
7238 volatile VALUE nval, exval;
7239 Data_Get_Struct(self, Molecule, mol);
7240 rb_scan_args(argc, argv, "1*", &nval, &exval);
7241 if (rb_obj_is_kind_of(nval, rb_cNumeric) || rb_obj_is_kind_of(nval, rb_cString)) {
7243 n = NUM2INT(s_Molecule_AtomIndex(self, nval));
7245 baseg = s_Molecule_AtomGroupFromValue(self, nval);
7247 if (RARRAY_LEN(exval) == 0) {
7250 exval = s_Molecule_AtomGroup(RARRAY_LEN(exval), RARRAY_PTR(exval), self);
7251 Data_Get_Struct(exval, IntGroup, exatoms);
7253 if (baseg == NULL) {
7254 ig = MoleculeFragmentExcludingAtomGroup(mol, n, exatoms);
7256 IntGroupIterator iter;
7257 IntGroupIteratorInit(baseg, &iter);
7258 if ((n = IntGroupIteratorNext(&iter)) < 0) {
7261 ig = MoleculeFragmentExcludingAtomGroup(mol, n, exatoms);
7263 while ((n = IntGroupIteratorNext(&iter)) >= 0) {
7265 subg = MoleculeFragmentExcludingAtomGroup(mol, n, exatoms);
7267 IntGroupAddIntGroup(ig, subg);
7268 IntGroupRelease(subg);
7273 IntGroupIteratorRelease(&iter);
7274 IntGroupRelease(baseg);
7277 rb_raise(rb_eMolbyError, "invalid specification of molecular fragment");
7278 nval = ValueFromIntGroup(ig);
7279 IntGroupRelease(ig);
7285 * each_fragment {|group| ...}
7287 * Execute the block, with the IntGroup object for each fragment as the argument.
7288 * Atoms or bonds should not be added or removed during the execution of the block.
7291 s_Molecule_EachFragment(VALUE self)
7296 Data_Get_Struct(self, Molecule, mol);
7297 if (mol == NULL || mol->natoms == 0)
7299 ag = IntGroupNewWithPoints(0, mol->natoms, -1);
7300 while (IntGroupGetCount(ag) > 0) {
7301 int n = IntGroupGetNthPoint(ag, 0);
7302 fg = MoleculeFragmentExcludingAtomGroup(mol, n, NULL);
7304 rb_raise(rb_eMolbyError, "internal error during each_fragment");
7305 gval = ValueFromIntGroup(fg);
7307 IntGroupRemoveIntGroup(ag, fg);
7308 IntGroupRelease(fg);
7310 IntGroupRelease(ag);
7316 * detachable?(group) -> [n1, n2]
7318 * Check whether the group is 'detachable', i.e. the group is bound to the rest
7319 * of the molecule via only one bond. If it is, then the indices of the atoms
7320 * belonging to the bond is returned, the first element being the atom included
7321 * in the fragment. Otherwise, Qnil is returned.
7324 s_Molecule_Detachable_P(VALUE self, VALUE gval)
7330 Data_Get_Struct(self, Molecule, mol);
7331 ig = s_Molecule_AtomGroupFromValue(self, gval);
7332 if (MoleculeIsFragmentDetachable(mol, ig, &n1, &n2)) {
7333 retval = rb_ary_new3(2, INT2NUM(n1), INT2NUM(n2));
7334 } else retval = Qnil;
7335 IntGroupRelease(ig);
7341 * bonds_on_border(group = selection) -> Array of Array of two Integers
7343 * Returns an array of bonds that connect an atom in the group and an atom out
7344 * of the group. The first atom in the bond always belongs to the group. If no
7345 * such bonds are present, an empty array is returned.
7348 s_Molecule_BondsOnBorder(int argc, VALUE *argv, VALUE self)
7353 Data_Get_Struct(self, Molecule, mol);
7354 rb_scan_args(argc, argv, "01", &gval);
7356 ig = MoleculeGetSelection(mol);
7360 ig = s_Molecule_AtomGroupFromValue(self, gval);
7362 retval = rb_ary_new();
7365 bg = MoleculeSearchBondsAcrossAtomGroup(mol, ig);
7367 IntGroupIterator iter;
7369 IntGroupIteratorInit(bg, &iter);
7370 while ((i = IntGroupIteratorNext(&iter)) >= 0) {
7371 /* The atoms at the border */
7373 n1 = mol->bonds[i * 2];
7374 n2 = mol->bonds[i * 2 + 1];
7375 if (IntGroupLookupPoint(ig, n1) < 0) {
7379 if (IntGroupLookupPoint(ig, n1) < 0)
7380 continue; /* Actually this is an internal error */
7382 rb_ary_push(retval, rb_ary_new3(2, INT2NUM(n1), INT2NUM(n2)));
7384 IntGroupIteratorRelease(&iter);
7386 IntGroupRelease(bg);
7387 IntGroupRelease(ig);
7393 * translate(vec, group = nil) -> Molecule
7395 * Translate the molecule by vec. If group is given, only atoms in the group are moved.
7396 * This operation is undoable.
7399 s_Molecule_Translate(int argc, VALUE *argv, VALUE self)
7405 Data_Get_Struct(self, Molecule, mol);
7406 rb_scan_args(argc, argv, "11", &vec, &group);
7407 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7408 VectorFromValue(vec, &v);
7409 // MoleculeTranslate(mol, &v, ig);
7410 MolActionCreateAndPerform(mol, gMolActionTranslateAtoms, &v, ig);
7412 IntGroupRelease(ig);
7418 * rotate(axis, angle, center = [0,0,0], group = nil) -> Molecule
7420 * Rotate the molecule. The axis must not a zero vector. angle is given in degree.
7421 * If group is given, only atoms in the group are moved.
7422 * This operation is undoable.
7425 s_Molecule_Rotate(int argc, VALUE *argv, VALUE self)
7428 volatile VALUE aval, anval, cval, gval;
7433 Data_Get_Struct(self, Molecule, mol);
7434 rb_scan_args(argc, argv, "22", &aval, &anval, &cval, &gval);
7435 ig = (NIL_P(gval) ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
7436 angle = NUM2DBL(rb_Float(anval)) * kDeg2Rad;
7437 VectorFromValue(aval, &av);
7439 cv.x = cv.y = cv.z = 0.0;
7441 VectorFromValue(cval, &cv);
7442 if (TransformForRotation(tr, &av, angle, &cv))
7443 rb_raise(rb_eMolbyError, "rotation axis cannot be a zero vector");
7444 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7446 IntGroupRelease(ig);
7452 * reflect(axis, center = [0,0,0], group = nil) -> Molecule
7454 * Reflect the molecule by the plane which is perpendicular to axis and including center.
7455 * axis must not be a zero vector.
7456 * If group is given, only atoms in the group are moved.
7457 * This operation is undoable.
7460 s_Molecule_Reflect(int argc, VALUE *argv, VALUE self)
7463 volatile VALUE aval, cval, gval;
7467 Data_Get_Struct(self, Molecule, mol);
7468 rb_scan_args(argc, argv, "12", &aval, &cval, &gval);
7469 ig = (NIL_P(gval) ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
7470 VectorFromValue(aval, &av);
7472 cv.x = cv.y = cv.z = 0.0;
7474 VectorFromValue(cval, &cv);
7475 if (TransformForReflection(tr, &av, &cv))
7476 rb_raise(rb_eMolbyError, "reflection axis cannot be a zero vector");
7477 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7479 IntGroupRelease(ig);
7485 * invert(center = [0,0,0], group = nil) -> Molecule
7487 * Invert the molecule with the given center.
7488 * If group is given, only atoms in the group are moved.
7489 * This operation is undoable.
7492 s_Molecule_Invert(int argc, VALUE *argv, VALUE self)
7495 volatile VALUE cval, gval;
7499 Data_Get_Struct(self, Molecule, mol);
7500 rb_scan_args(argc, argv, "02", &cval, &gval);
7501 ig = (NIL_P(gval) ? NULL : s_Molecule_AtomGroupFromValue(self, gval));
7503 cv.x = cv.y = cv.z = 0.0;
7505 VectorFromValue(cval, &cv);
7506 TransformForInversion(tr, &cv);
7507 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7509 IntGroupRelease(ig);
7515 * transform(transform, group = nil) -> Molecule
7517 * Transform the molecule by the given Transform object.
7518 * If group is given, only atoms in the group are moved.
7519 * This operation is undoable.
7522 s_Molecule_Transform(int argc, VALUE *argv, VALUE self)
7528 Data_Get_Struct(self, Molecule, mol);
7529 rb_scan_args(argc, argv, "11", &trans, &group);
7530 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7531 TransformFromValue(trans, &tr);
7532 /* MoleculeTransform(mol, tr, ig); */
7533 MolActionCreateAndPerform(mol, gMolActionTransformAtoms, &tr, ig);
7535 IntGroupRelease(ig);
7540 s_Molecule_DoCenterOfMass(Molecule *mol, Vector *outv, IntGroup *ig)
7542 switch (MoleculeCenterOfMass(mol, outv, ig)) {
7543 case 2: rb_raise(rb_eMolbyError, "atom group is empty"); break;
7544 case 3: rb_raise(rb_eMolbyError, "weight is zero --- atomic weights are not defined?"); break;
7546 default: rb_raise(rb_eMolbyError, "cannot calculate center of mass"); break;
7552 * center_of_mass(group = nil) -> Vector3D
7554 * Calculate the center of mass for the given set of atoms. The argument
7555 * group is null, then all atoms are considered.
7558 s_Molecule_CenterOfMass(int argc, VALUE *argv, VALUE self)
7564 Data_Get_Struct(self, Molecule, mol);
7565 rb_scan_args(argc, argv, "01", &group);
7566 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7567 s_Molecule_DoCenterOfMass(mol, &v, ig);
7569 IntGroupRelease(ig);
7570 return ValueFromVector(&v);
7575 * centralize(group = nil) -> self
7577 * Translate the molecule so that the center of mass of the given group is located
7578 * at (0, 0, 0). Equivalent to molecule.translate(molecule.center_of_mass(group) * -1).
7581 s_Molecule_Centralize(int argc, VALUE *argv, VALUE self)
7587 Data_Get_Struct(self, Molecule, mol);
7588 rb_scan_args(argc, argv, "01", &group);
7589 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7590 s_Molecule_DoCenterOfMass(mol, &v, ig);
7592 IntGroupRelease(ig);
7596 MolActionCreateAndPerform(mol, gMolActionTranslateAtoms, &v, NULL);
7602 * bounds(group = nil) -> [min, max]
7604 * Calculate the boundary. The return value is an array of two Vector3D objects.
7607 s_Molecule_Bounds(int argc, VALUE *argv, VALUE self)
7615 Data_Get_Struct(self, Molecule, mol);
7616 rb_scan_args(argc, argv, "01", &group);
7617 ig = (NIL_P(group) ? NULL : s_Molecule_AtomGroupFromValue(self, group));
7618 if (ig != NULL && IntGroupGetCount(ig) == 0)
7619 rb_raise(rb_eMolbyError, "atom group is empty");
7620 vmin.x = vmin.y = vmin.z = 1e30;
7621 vmax.x = vmax.y = vmax.z = -1e30;
7622 for (n = 0, ap = mol->atoms; n < mol->natoms; n++, ap = ATOM_NEXT(ap)) {
7624 if (ig != NULL && IntGroupLookup(ig, n, NULL) == 0)
7640 return rb_ary_new3(2, ValueFromVector(&vmin), ValueFromVector(&vmax));
7643 /* Get atom position or a vector */
7645 s_Molecule_GetVectorFromArg(Molecule *mol, VALUE val, Vector *vp)
7647 if (rb_obj_is_kind_of(val, rb_cInteger) || rb_obj_is_kind_of(val, rb_cString)) {
7648 int n1 = s_Molecule_AtomIndexFromValue(mol, val);
7649 *vp = ATOM_AT_INDEX(mol->atoms, n1)->r;
7651 VectorFromValue(val, vp);
7657 * measure_bond(n1, n2) -> Float
7659 * Calculate the bond length. The arguments can either be atom indices, the "residue:name" representation,
7660 * or Vector3D values.
7661 * If the crystallographic cell is defined, then the internal coordinates are convereted to the cartesian.
7664 s_Molecule_MeasureBond(VALUE self, VALUE nval1, VALUE nval2)
7668 Data_Get_Struct(self, Molecule, mol);
7669 s_Molecule_GetVectorFromArg(mol, nval1, &v1);
7670 s_Molecule_GetVectorFromArg(mol, nval2, &v2);
7671 return rb_float_new(MoleculeMeasureBond(mol, &v1, &v2));
7676 * measure_angle(n1, n2, n3) -> Float
7678 * Calculate the bond angle. The arguments can either be atom indices, the "residue:name" representation,
7679 * or Vector3D values. The return value is in degree.
7680 * If the crystallographic cell is defined, then the internal coordinates are convereted to the cartesian.
7683 s_Molecule_MeasureAngle(VALUE self, VALUE nval1, VALUE nval2, VALUE nval3)
7688 Data_Get_Struct(self, Molecule, mol);
7689 s_Molecule_GetVectorFromArg(mol, nval1, &v1);
7690 s_Molecule_GetVectorFromArg(mol, nval2, &v2);
7691 s_Molecule_GetVectorFromArg(mol, nval3, &v3);
7692 d = MoleculeMeasureAngle(mol, &v1, &v2, &v3);
7694 return Qnil; /* Cannot define */
7695 else return rb_float_new(d);
7700 * measure_dihedral(n1, n2, n3, n4) -> Float
7702 * Calculate the dihedral angle. The arguments can either be atom indices, the "residue:name" representation,
7703 * or Vector3D values. The return value is in degree.
7704 * If the crystallographic cell is defined, then the internal coordinates are convereted to the cartesian.
7707 s_Molecule_MeasureDihedral(VALUE self, VALUE nval1, VALUE nval2, VALUE nval3, VALUE nval4)
7710 Vector v1, v2, v3, v4;
7712 Data_Get_Struct(self, Molecule, mol);
7713 s_Molecule_GetVectorFromArg(mol, nval1, &v1);
7714 s_Molecule_GetVectorFromArg(mol, nval2, &v2);
7715 s_Molecule_GetVectorFromArg(mol, nval3, &v3);
7716 s_Molecule_GetVectorFromArg(mol, nval4, &v4);
7717 d = MoleculeMeasureDihedral(mol, &v1, &v2, &v3, &v4);
7719 return Qnil; /* Cannot define */
7720 else return rb_float_new(d);
7725 * expand_by_symmetry(group, sym, dx=0, dy=0, dz=0) -> Array
7727 * Expand the specified part of the molecule by the given symmetry operation.
7728 * Returns the array of atom indices corresponding to the expanded atoms.
7731 s_Molecule_ExpandBySymmetry(int argc, VALUE *argv, VALUE self)
7734 VALUE gval, sval, xval, yval, zval, rval;
7740 Data_Get_Struct(self, Molecule, mol);
7741 rb_scan_args(argc, argv, "23", &gval, &sval, &xval, &yval, &zval);
7742 n[0] = NUM2INT(rb_Integer(sval));
7743 n[1] = (xval == Qnil ? 0 : NUM2INT(rb_Integer(xval)));
7744 n[2] = (yval == Qnil ? 0 : NUM2INT(rb_Integer(yval)));
7745 n[3] = (zval == Qnil ? 0 : NUM2INT(rb_Integer(zval)));
7746 ig = s_Molecule_AtomGroupFromValue(self, gval);
7747 if (n[0] < 0 || n[0] >= mol->nsyms)
7748 rb_raise(rb_eMolbyError, "symmetry index is out of bounds");
7749 natoms = mol->natoms;
7751 MolActionCreateAndPerform(mol, gMolActionExpandBySymmetry, ig, n[1], n[2], n[3], n[0], &nidx, &idx);
7753 rval = rb_ary_new2(nidx);
7754 while (--nidx >= 0) {
7755 rb_ary_store(rval, nidx, INT2NUM(idx[nidx]));
7757 /* if (natoms == mol->natoms)
7760 rval = IntGroup_Alloc(rb_cIntGroup);
7761 Data_Get_Struct(rval, IntGroup, ig);
7762 IntGroup_RaiseIfError(IntGroupAdd(ig, natoms, mol->natoms - natoms));
7769 * amend_by_symmetry(group = nil) -> IntGroup
7771 * Expand the specified part of the molecule by the given symmetry operation.
7772 * Returns an IntGroup containing the added atoms.
7775 s_Molecule_AmendBySymmetry(int argc, VALUE *argv, VALUE self)
7780 Data_Get_Struct(self, Molecule, mol);
7781 rb_scan_args(argc, argv, "01", &gval);
7783 ig = s_Molecule_AtomGroupFromValue(self, gval);
7785 MolActionCreateAndPerform(mol, gMolActionAmendBySymmetry, ig, &ig2);
7786 rval = ValueFromIntGroup(ig2);
7787 IntGroupRelease(ig2);
7793 * transform_for_symop(symop, is_cartesian = nil) -> Transform
7795 * Get the transform corresponding to the symmetry operation. The symop can either be
7796 * an integer (index of symmetry operation) or [sym, dx, dy, dz].
7797 * If is_cartesian is true, the returned transform is for cartesian coordinates.
7798 * Otherwise, the returned transform is for fractional coordinates.
7799 * Raises exception when no cell or no transform are defined.
7802 s_Molecule_TransformForSymop(int argc, VALUE *argv, VALUE self)
7808 Data_Get_Struct(self, Molecule, mol);
7809 if (mol->cell == NULL)
7810 rb_raise(rb_eMolbyError, "no unit cell is defined");
7811 if (mol->nsyms == 0)
7812 rb_raise(rb_eMolbyError, "no symmetry operation is defined");
7813 rb_scan_args(argc, argv, "11", &sval, &fval);
7814 if (rb_obj_is_kind_of(sval, rb_cNumeric)) {
7815 symop.sym = NUM2INT(rb_Integer(sval));
7816 symop.dx = symop.dy = symop.dz = 0;
7818 sval = rb_ary_to_ary(sval);
7819 if (RARRAY_LEN(sval) < 4)
7820 rb_raise(rb_eMolbyError, "missing arguments as symop; at least four integers should be given");
7821 symop.sym = NUM2INT(rb_Integer(RARRAY_PTR(sval)[0]));
7822 symop.dx = NUM2INT(rb_Integer(RARRAY_PTR(sval)[1]));
7823 symop.dy = NUM2INT(rb_Integer(RARRAY_PTR(sval)[2]));
7824 symop.dz = NUM2INT(rb_Integer(RARRAY_PTR(sval)[3]));
7826 if (symop.sym >= mol->nsyms)
7827 rb_raise(rb_eMolbyError, "index of symmetry operation (%d) is out of range", symop.sym);
7828 MoleculeGetTransformForSymop(mol, symop, &tr, (RTEST(fval) != 0));
7829 return ValueFromTransform(&tr);
7834 * symop_for_transform(transform, is_cartesian = nil) -> [sym, dx, dy, dz]
7836 * Get the symmetry operation corresponding to the given transform.
7837 * If is_cartesian is true, the given transform is for cartesian coordinates.
7838 * Otherwise, the given transform is for fractional coordinates.
7839 * Raises exception when no cell or no transform are defined.
7842 s_Molecule_SymopForTransform(int argc, VALUE *argv, VALUE self)
7849 Data_Get_Struct(self, Molecule, mol);
7850 if (mol->cell == NULL)
7851 rb_raise(rb_eMolbyError, "no unit cell is defined");
7852 if (mol->nsyms == 0)
7853 rb_raise(rb_eMolbyError, "no symmetry operation is defined");
7854 rb_scan_args(argc, argv, "11", &tval, &fval);
7855 TransformFromValue(tval, &tr);
7856 n = MoleculeGetSymopForTransform(mol, tr, &symop, (RTEST(fval) != 0));
7858 return rb_ary_new3(4, INT2NUM(symop.sym), INT2NUM(symop.dx), INT2NUM(symop.dy), INT2NUM(symop.dz));
7860 return Qnil; /* Not found */
7866 * wrap_unit_cell(group) -> Vector3D
7868 * Move the specified group so that the center of mass of the group is within the
7869 * unit cell. The offset vector is returned. If no periodic box is defined,
7870 * exception is raised.
7873 s_Molecule_WrapUnitCell(VALUE self, VALUE gval)
7878 Data_Get_Struct(self, Molecule, mol);
7879 if (mol->cell == NULL)
7880 rb_raise(rb_eMolbyError, "no unit cell is defined");
7881 ig = s_Molecule_AtomGroupFromValue(self, gval);
7882 s_Molecule_DoCenterOfMass(mol, &cv, ig);
7883 TransformVec(&v, mol->cell->rtr, &cv);
7884 if (mol->cell->flags[0])
7886 if (mol->cell->flags[1])
7888 if (mol->cell->flags[2])
7890 TransformVec(&dv, mol->cell->tr, &v);
7892 MolActionCreateAndPerform(mol, gMolActionTranslateAtoms, &dv, ig);
7893 IntGroupRelease(ig);
7894 return ValueFromVector(&dv);
7899 * find_conflicts(limit[, group1[, group2 [, ignore_exclusion]]]) -> [[n1, n2], [n3, n4], ...]
7901 * Find pairs of atoms that are within the limit distance. If group1 and group2 are given, the
7902 * first and second atom in the pair should belong to group1 and group2, respectively.
7903 * If ignore_exclusion is true, then 1-2 (bonded), 1-3, 1-4 pairs are also considered.
7906 s_Molecule_FindConflicts(int argc, VALUE *argv, VALUE self)
7909 VALUE limval, gval1, gval2, rval, igval;
7910 IntGroup *ig1, *ig2;
7911 IntGroupIterator iter1, iter2;
7917 MDExclusion *exinfo;
7920 Data_Get_Struct(self, Molecule, mol);
7921 rb_scan_args(argc, argv, "13", &limval, &gval1, &gval2, &igval);
7922 lim = NUM2DBL(rb_Float(limval));
7924 rb_raise(rb_eMolbyError, "the limit (%g) should be positive", lim);
7926 ig1 = s_Molecule_AtomGroupFromValue(self, gval1);
7928 ig1 = IntGroupNewWithPoints(0, mol->natoms, -1);
7930 ig2 = s_Molecule_AtomGroupFromValue(self, gval2);
7932 ig2 = IntGroupNewWithPoints(0, mol->natoms, -1);
7934 if (!RTEST(igval)) {
7935 /* Use the exclusion table in MDArena */
7936 if (mol->par == NULL || mol->arena == NULL || mol->arena->is_initialized == 0 || mol->needsMDRebuild) {
7937 VALUE mval = ValueFromMolecule(mol);
7938 s_RebuildMDParameterIfNecessary(mval, Qnil);
7940 exinfo = mol->arena->exinfo; /* May be NULL */
7941 exlist = mol->arena->exlist;
7946 IntGroupIteratorInit(ig1, &iter1);
7947 IntGroupIteratorInit(ig2, &iter2);
7950 while ((n[0] = IntGroupIteratorNext(&iter1)) >= 0) {
7952 ap1 = ATOM_AT_INDEX(mol->atoms, n[0]);
7954 if (exinfo != NULL) {
7955 exn1 = exinfo[n[0]].index1;
7956 exn2 = exinfo[n[0] + 1].index1;
7957 } else exn1 = exn2 = -1;
7958 IntGroupIteratorReset(&iter2);
7959 while ((n[1] = IntGroupIteratorNext(&iter2)) >= 0) {
7960 ap2 = ATOM_AT_INDEX(mol->atoms, n[1]);
7962 continue; /* Same atom */
7963 if (exinfo != NULL) {
7964 /* Look up exclusion table to exclude 1-2, 1-3, and 1-4 pairs */
7965 for (i = exn1; i < exn2; i++) {
7966 if (exlist[i] == n[1])
7970 continue; /* Should be excluded */
7972 if (MoleculeMeasureBond(mol, &r1, &(ap2->r)) < lim) {
7973 /* Is this pair already registered? */
7975 for (i = 0, ip = pairs; i < npairs; i++, ip += 2) {
7976 if ((ip[0] == n[0] && ip[1] == n[1]) || (ip[0] == n[1] && ip[1] == n[0]))
7980 /* Not registered yet */
7981 AssignArray(&pairs, &npairs, sizeof(Int) * 2, npairs, n);
7986 IntGroupIteratorRelease(&iter2);
7987 IntGroupIteratorRelease(&iter1);
7988 IntGroupRelease(ig2);
7989 IntGroupRelease(ig1);
7990 rval = rb_ary_new2(npairs);
7991 if (pairs != NULL) {
7992 for (i = 0; i < npairs; i++) {
7993 rb_ary_push(rval, rb_ary_new3(2, INT2NUM(pairs[i * 2]), INT2NUM(pairs[i * 2 + 1])));
8000 /* Calculate the transform that moves the current coordinates to the reference
8001 coordinates with least displacements. */
8003 s_Molecule_FitCoordinates_Sub(Molecule *mol, IntGroup *ig, Vector *ref, Double *weights, Transform trans)
8011 Double eigen_val[3];
8012 Vector eigen_vec[3];
8014 IntGroupIterator iter;
8016 natoms = mol->natoms;
8018 IntGroupIteratorInit(ig, &iter);
8020 /* Calculate the weighted center */
8024 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8025 ap1 = ATOM_AT_INDEX(ap, in);
8026 w1 = (weights != NULL ? weights[i] : ap1->weight);
8027 VecScaleInc(org1, ap1->r, w1);
8028 VecScaleInc(org2, ref[i], w1);
8032 VecScaleSelf(org1, w);
8033 VecScaleSelf(org2, w);
8035 /* R = sum(weight[n]^2 * x[n] * t(y[n])); */
8036 /* Matrix to diagonalize = R * tR */
8037 memset(r, 0, sizeof(Mat33));
8038 memset(q, 0, sizeof(Mat33));
8039 memset(u, 0, sizeof(Mat33));
8041 IntGroupIteratorReset(&iter);
8042 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8044 ap1 = ATOM_AT_INDEX(ap, in);
8045 w1 = (weights != NULL ? weights[i] : ap1->weight);
8047 VecSub(v1, ap1->r, org1);
8048 VecSub(v2, ref[i], org2);
8049 r[0] += w1 * v1.x * v2.x;
8050 r[1] += w1 * v1.y * v2.x;
8051 r[2] += w1 * v1.z * v2.x;
8052 r[3] += w1 * v1.x * v2.y;
8053 r[4] += w1 * v1.y * v2.y;
8054 r[5] += w1 * v1.z * v2.y;
8055 r[6] += w1 * v1.x * v2.z;
8056 r[7] += w1 * v1.y * v2.z;
8057 r[8] += w1 * v1.z * v2.z;
8060 for (i = 0; i < 9; i++)
8062 for (i = 0; i < 3; i++) {
8063 for (j = 0; j < 3; j++) {
8064 for (k = 0; k < 3; k++) {
8065 q[i+j*3] += r[i+k*3] * r[j+k*3];
8070 if (MatrixSymDiagonalize(q, eigen_val, eigen_vec) != 0) {
8071 IntGroupIteratorRelease(&iter);
8072 return -1.0; /* Cannot determine the eigenvector */
8075 /* s[i] = tR * v[i] / sqrt(eigenval[i]) */
8076 /* U = s0*t(v0) + s1*t(v1) + s2*t(v2) */
8077 MatrixTranspose(r, r);
8078 for (i = 0; i < 3; i++) {
8079 MatrixVec(&s[i], r, &eigen_vec[i]);
8080 w1 = 1.0 / sqrt(eigen_val[i]);
8081 VecScaleSelf(s[i], w1);
8083 for (k = 0; k < 3; k++) {
8084 u[0] += s[k].x * eigen_vec[k].x;
8085 u[1] += s[k].y * eigen_vec[k].x;
8086 u[2] += s[k].z * eigen_vec[k].x;
8087 u[3] += s[k].x * eigen_vec[k].y;
8088 u[4] += s[k].y * eigen_vec[k].y;
8089 u[5] += s[k].z * eigen_vec[k].y;
8090 u[6] += s[k].x * eigen_vec[k].z;
8091 u[7] += s[k].y * eigen_vec[k].z;
8092 u[8] += s[k].z * eigen_vec[k].z;
8095 /* y = U*(x - org1) + org2 = U*x + (org2 - U*org1) */
8096 MatrixVec(&org1, u, &org1);
8098 for (i = 0; i < 9; i++)
8104 /* Calculate rmsd */
8105 IntGroupIteratorReset(&iter);
8107 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8109 ap1 = ATOM_AT_INDEX(ap, in);
8110 TransformVec(&tv, trans, &ap1->r);
8112 w += VecLength2(tv);
8115 IntGroupIteratorRelease(&iter);
8121 * fit_coordinates(group, ref, weight = nil) -> [transform, rmsd]
8123 * Calculate the transform to fit the given group to the set of reference coordinates.
8124 * The reference coordinates ref is given as either a frame number, an array of
8125 * Vector3Ds or arrays, or an LAMatrix. Weight can be optionally given as an array
8126 * of numbers or an LAMatrix. If weight is not given, the atomic weights are used.
8127 * Return values are the transform (that converts the present coordinates to the
8128 * target coordinates) and root mean square deviation (without weight).
8131 s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
8135 VALUE gval, rval, wval;
8137 IntGroupIterator iter;
8138 int nn, errno, i, j, in, status;
8140 Double *weights, dval[3];
8143 Data_Get_Struct(self, Molecule, mol);
8144 rb_scan_args(argc, argv, "21", &gval, &rval, &wval);
8146 ig = IntGroupNewWithPoints(0, mol->natoms, -1);
8148 ig = IntGroupFromValue(gval);
8149 if (ig == NULL || (nn = IntGroupGetCount(ig)) == 0) {
8150 IntGroupRelease(ig);
8151 rb_raise(rb_eMolbyError, "atom group is not given correctly");
8153 ref = (Vector *)calloc(sizeof(Vector), nn);
8154 weights = (Double *)calloc(sizeof(Double), nn);
8155 IntGroupIteratorInit(ig, &iter);
8156 if (rb_obj_is_kind_of(rval, rb_cNumeric)) {
8157 int fn = NUM2INT(rb_Integer(rval));
8158 if (fn < 0 || fn >= MoleculeGetNumberOfFrames(mol)) {
8163 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8164 ap = ATOM_AT_INDEX(mol->atoms, in);
8165 if (fn < ap->nframes)
8166 ref[i] = ap->frames[fn];
8167 else ref[i] = ap->r;
8169 } else if (rb_obj_is_kind_of(rval, rb_cLAMatrix)) {
8170 LAMatrix *m = LAMatrixFromValue(rval, NULL, 0, 0);
8171 if (m->row * m->column < nn * 3) {
8175 for (i = 0; i < nn; i++) {
8176 ref[i].x = m->data[i * 3];
8177 ref[i].y = m->data[i * 3 + 1];
8178 ref[i].z = m->data[i * 3 + 2];
8182 rval = rb_protect(rb_ary_to_ary, rval, &status);
8187 if (RARRAY_LEN(rval) < nn) {
8191 if (rb_obj_is_kind_of((RARRAY_PTR(rval))[0], rb_cNumeric)) {
8192 /* Array of 3*nn numbers */
8193 if (RARRAY_LEN(rval) < nn * 3) {
8197 for (i = 0; i < nn; i++) {
8198 for (j = 0; j < 3; j++) {
8199 aval = rb_protect(rb_Float, (RARRAY_PTR(rval))[i * 3 + j], &status);
8204 dval[j] = NUM2DBL(aval);
8211 /* Array of nn Vector3Ds or Arrays */
8212 for (i = 0; i < nn; i++) {
8213 aval = (RARRAY_PTR(rval))[i];
8214 if (rb_obj_is_kind_of(aval, rb_cVector3D)) {
8215 VectorFromValue(aval, &ref[i]);
8217 aval = rb_protect(rb_ary_to_ary, aval, &status);
8222 if (RARRAY_LEN(aval) < 3) {
8227 for (j = 0; j < 3; j++) {
8228 VALUE aaval = rb_protect(rb_Float, (RARRAY_PTR(aval))[j], &status);
8233 dval[j] = NUM2DBL(aaval);
8243 /* Use atomic weights */
8244 IntGroupIteratorReset(&iter);
8245 for (i = 0; (in = IntGroupIteratorNext(&iter)) >= 0; i++) {
8246 ap = ATOM_AT_INDEX(mol->atoms, in);
8247 weights[i] = ap->weight;
8250 wval = rb_protect(rb_ary_to_ary, wval, &status);
8255 if (RARRAY_LEN(wval) < nn) {
8259 for (i = 0; i < nn; i++) {
8260 VALUE wwval = rb_protect(rb_Float, (RARRAY_PTR(wval))[i], &status);
8265 weights[i] = NUM2DBL(wwval);
8268 dval[0] = s_Molecule_FitCoordinates_Sub(mol, ig, ref, weights, tr);
8275 IntGroupIteratorRelease(&iter);
8279 return rb_ary_new3(2, ValueFromTransform(&tr), rb_float_new(dval[0]));
8280 } else if (errno == 1) {
8281 rb_raise(rb_eMolbyError, "frame index (%d) is out of range", status);
8282 } else if (errno == 2) {
8283 rb_raise(rb_eMolbyError, "insufficient number of reference coordinates");
8284 } else if (errno == 3) {
8285 rb_jump_tag(status);
8286 } else if (errno == 4) {
8287 rb_raise(rb_eMolbyError, "less than 3 elements for index %d of reference coordinates", status);
8288 } else if (errno == 5) {
8289 rb_raise(rb_eMolbyError, "insufficient number of weight values");
8290 } else if (errno == 6) {
8291 rb_raise(rb_eMolbyError, "matrix calculation failed during coordinate fitting");
8293 return Qnil; /* Not reached */
8300 * Refresh the display if this molecule is bound to a view. Otherwise do nothing.
8303 s_Molecule_Display(VALUE self)
8306 Data_Get_Struct(self, Molecule, mol);
8307 if (mol->mview != NULL)
8308 MainViewCallback_display(mol->mview);
8316 * Make the window frontmost if this molecule is bound to a view. Otherwise do nothing.
8319 s_Molecule_MakeFront(VALUE self)
8322 Data_Get_Struct(self, Molecule, mol);
8323 if (mol->mview != NULL)
8324 MainViewCallback_makeFront(mol->mview);
8330 * update_enabled? -> bool
8332 * Returns true if screen update is enabled; otherwise no.
8335 s_Molecule_UpdateEnabled(VALUE self)
8338 Data_Get_Struct(self, Molecule, mol);
8339 if (mol->mview != NULL && !mol->mview->freezeScreen)
8346 * update_enabled = bool
8348 * Enable or disable screen update. This is effective for automatic update on modification.
8349 * Explicit call to molecule.display() always updates the screen.
8352 s_Molecule_SetUpdateEnabled(VALUE self, VALUE val)
8355 Data_Get_Struct(self, Molecule, mol);
8356 val = ((val != Qfalse && val != Qnil) ? Qtrue : Qfalse);
8357 if (mol->mview != NULL)
8358 mol->mview->freezeScreen = (val == Qfalse);
8366 * show_unitcell(bool)
8367 * show_unitcell = bool
8369 * Set the flag whether to show the unit cell. If no argument is given, the
8370 * current flag is returned.
8373 s_Molecule_ShowUnitCell(int argc, VALUE *argv, VALUE self)
8376 Data_Get_Struct(self, Molecule, mol);
8377 if (mol->mview == NULL)
8380 mol->mview->showUnitCell = (RTEST(argv[0]) != 0);
8381 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8383 return (mol->mview->showUnitCell ? Qtrue : Qfalse);
8389 * show_hydrogens(bool)
8390 * show_hydrogens = bool
8392 * Set the flag whether to show the hydrogen atoms. If no argument is given, the
8393 * current flag is returned.
8396 s_Molecule_ShowHydrogens(int argc, VALUE *argv, VALUE self)
8399 Data_Get_Struct(self, Molecule, mol);
8400 if (mol->mview == NULL)
8403 mol->mview->showHydrogens = (RTEST(argv[0]) != 0);
8404 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8406 return (mol->mview->showHydrogens ? Qtrue : Qfalse);
8412 * show_dummy_atoms(bool)
8413 * show_dummy_atoms = bool
8415 * Set the flag whether to show the dummy atoms. If no argument is given, the
8416 * current flag is returned.
8419 s_Molecule_ShowDummyAtoms(int argc, VALUE *argv, VALUE self)
8422 Data_Get_Struct(self, Molecule, mol);
8423 if (mol->mview == NULL)
8426 mol->mview->showDummyAtoms = (RTEST(argv[0]) != 0);
8427 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8429 return (mol->mview->showDummyAtoms ? Qtrue : Qfalse);
8435 * show_expanded(bool)
8436 * show_expanded = bool
8438 * Set the flag whether to show the expanded atoms. If no argument is given, the
8439 * current flag is returned.
8442 s_Molecule_ShowExpanded(int argc, VALUE *argv, VALUE self)
8445 Data_Get_Struct(self, Molecule, mol);
8446 if (mol->mview == NULL)
8449 mol->mview->showExpandedAtoms = (RTEST(argv[0]) != 0);
8450 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8452 return (mol->mview->showExpandedAtoms ? Qtrue : Qfalse);
8458 * show_ellipsoids(bool)
8459 * show_ellipsoids = bool
8461 * Set the flag whether to show the thermal ellipsoids. If no argument is given, the
8462 * current flag is returned.
8465 s_Molecule_ShowEllipsoids(int argc, VALUE *argv, VALUE self)
8468 Data_Get_Struct(self, Molecule, mol);
8469 if (mol->mview == NULL)
8472 mol->mview->showEllipsoids = (RTEST(argv[0]) != 0);
8473 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8475 return (mol->mview->showEllipsoids ? Qtrue : Qfalse);
8480 * is_atom_visible(index) -> Boolean
8482 * Check is an atom is visible. It examines the atom attribute (ap->exflags & kAtomHiddenFlag)
8483 * as well as the molecule attributes (showHydrogens, etc.)
8486 s_Molecule_IsAtomVisible(VALUE self, VALUE ival)
8491 Data_Get_Struct(self, Molecule, mol);
8492 idx = s_Molecule_AtomIndexFromValue(mol, ival);
8493 if (idx < 0 || idx >= mol->natoms)
8495 ap = ATOM_AT_INDEX(mol->atoms, idx);
8496 if (mol->mview != NULL) {
8497 if (mol->mview->showHydrogens == 0 && ap->atomicNumber == 1)
8499 if (mol->mview->showExpandedAtoms == 0 && SYMOP_ALIVE(ap->symop))
8501 if (mol->mview->showDummyAtoms == 0 && ap->atomicNumber == 0)
8504 return ((ap->exflags & kAtomHiddenFlag) != 0 ? Qfalse : Qtrue);
8509 * show_graphite -> Integer
8510 * show_graphite = Integer
8511 * show_graphite = boolean
8513 * Set whether to show the graphite plane. If the argument is positive, it also indicates the
8514 * number of rings to display for each direction.
8515 * If the argument is boolean, only the show/hide flag is set.
8518 s_Molecule_ShowGraphite(int argc, VALUE *argv, VALUE self)
8521 Data_Get_Struct(self, Molecule, mol);
8522 if (mol->mview == NULL)
8525 if (argv[0] == Qnil || argv[0] == Qfalse)
8526 mol->mview->showGraphiteFlag = 0;
8527 else if (argv[0] == Qtrue)
8528 mol->mview->showGraphiteFlag = 1;
8530 int n = NUM2INT(rb_Integer(argv[0]));
8532 rb_raise(rb_eMolbyError, "The argument must be non-negative integer");
8533 mol->mview->showGraphite = n;
8535 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8537 return INT2NUM(mol->mview->showGraphite);
8542 * show_graphite? -> boolean
8544 * Return whether the graphite is set visible or not.
8547 s_Molecule_ShowGraphiteFlag(VALUE self)
8550 Data_Get_Struct(self, Molecule, mol);
8551 if (mol->mview == NULL)
8553 return (mol->mview->showGraphiteFlag ? Qtrue : Qfalse);
8558 * show_periodic_image -> [amin, amax, bmin, bmax, cmin, cmax]
8559 * show_periodic_image = [amin, amax, bmin, bmax, cmin, cmax]
8560 * show_periodic_image = boolean
8562 * Set to show the periodic image of the atoms. If the unit cell is not defined, the values are
8563 * set but no visual effects are observed.
8564 * If the argument is boolean, only the show/hide flag is modified.
8567 s_Molecule_ShowPeriodicImage(int argc, VALUE *argv, VALUE self)
8573 Data_Get_Struct(self, Molecule, mol);
8574 if (mol->mview == NULL)
8576 rb_scan_args(argc, argv, "01", &val);
8578 /* Change current settings */
8579 if (val == Qnil || val == Qfalse)
8580 mol->mview->showPeriodicImageFlag = 0;
8581 else if (val == Qtrue)
8582 mol->mview->showPeriodicImageFlag = 1;
8584 val = rb_ary_to_ary(val);
8585 for (i = 0; i < 6; i++) {
8586 if (i < RARRAY_LEN(val))
8587 ival[i] = NUM2INT(rb_Integer(RARRAY_PTR(val)[i]));
8589 if (ival[0] > 0 || ival[1] < 0 || ival[2] > 0 || ival[3] < 0 || ival[4] > 0 || ival[5] < 0)
8590 rb_raise(rb_eMolbyError, "bad arguments");
8591 for (i = 0; i < 6; i++)
8592 mol->mview->showPeriodicImage[i] = ival[i];
8594 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8597 for (i = 0; i < 6; i++)
8598 rb_ary_push(val, INT2NUM(mol->mview->showPeriodicImage[i]));
8604 * show_periodic_image? -> boolean
8606 * Return whether the periodic images are set to visible or not. This flag is
8607 * independent from the show_periodic_image settings.
8610 s_Molecule_ShowPeriodicImageFlag(VALUE self)
8613 Data_Get_Struct(self, Molecule, mol);
8614 if (mol->mview == NULL)
8616 return (mol->mview->showPeriodicImageFlag ? Qtrue : Qfalse);
8625 * Set the flag whether to draw the model in line mode. If no argument is given, the
8626 * current flag is returned.
8629 s_Molecule_LineMode(int argc, VALUE *argv, VALUE self)
8632 Data_Get_Struct(self, Molecule, mol);
8633 if (mol->mview == NULL)
8636 mol->mview->lineMode = (RTEST(argv[0]) != 0);
8637 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8639 return (mol->mview->lineMode ? Qtrue : Qfalse);
8646 * Resize the model drawing to fit in the window.
8649 s_Molecule_ResizeToFit(VALUE self)
8652 Data_Get_Struct(self, Molecule, mol);
8653 if (mol->mview != NULL)
8654 MainView_resizeToFit(mol->mview);
8660 * get_view_rotation -> [[ax, ay, az], angle]
8662 * Get the current rotation for the view. Angle is in degree, not radian.
8665 s_Molecule_GetViewRotation(VALUE self)
8670 Data_Get_Struct(self, Molecule, mol);
8671 if (mol->mview == NULL)
8673 TrackballGetRotate(mol->mview->track, f);
8674 f[0] = -f[0]; /* Convert to left-handed screw (to be consistent with Transform) */
8678 return rb_ary_new3(2, ValueFromVector(&v), rb_float_new(f[0]));
8683 * get_view_scale -> float
8685 * Get the current scale for the view.
8688 s_Molecule_GetViewScale(VALUE self)
8691 Data_Get_Struct(self, Molecule, mol);
8692 if (mol->mview == NULL)
8694 return rb_float_new(TrackballGetScale(mol->mview->track));
8699 * get_view_center -> Vector
8701 * Get the current center point of the view.
8704 s_Molecule_GetViewCenter(VALUE self)
8709 Data_Get_Struct(self, Molecule, mol);
8710 if (mol->mview == NULL)
8712 TrackballGetTranslate(mol->mview->track, f);
8713 v.x = -f[0] * mol->mview->dimension;
8714 v.y = -f[1] * mol->mview->dimension;
8715 v.z = -f[2] * mol->mview->dimension;
8716 return ValueFromVector(&v);
8721 * set_view_rotation([ax, ay, az], angle) -> self
8723 * Set the current rotation for the view. Angle is in degree, not radian.
8726 s_Molecule_SetViewRotation(VALUE self, VALUE aval, VALUE angval)
8731 Data_Get_Struct(self, Molecule, mol);
8732 if (mol->mview == NULL)
8734 VectorFromValue(aval, &v);
8735 if (NormalizeVec(&v, &v))
8736 rb_raise(rb_eMolbyError, "Cannot normalize nearly zero vector");
8740 f[0] = -NUM2DBL(rb_Float(angval));
8741 TrackballSetRotate(mol->mview->track, f);
8742 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8748 * set_view_scale(scale) -> self
8750 * Set the current scale for the view.
8753 s_Molecule_SetViewScale(VALUE self, VALUE aval)
8756 Data_Get_Struct(self, Molecule, mol);
8757 if (mol->mview == NULL)
8759 TrackballSetScale(mol->mview->track, NUM2DBL(rb_Float(aval)));
8760 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8766 * set_view_center(vec) -> self
8768 * Set the current center point of the view.
8771 s_Molecule_SetViewCenter(VALUE self, VALUE aval)
8776 Data_Get_Struct(self, Molecule, mol);
8777 if (mol->mview == NULL)
8779 VectorFromValue(aval, &v);
8780 f[0] = -v.x / mol->mview->dimension;
8781 f[1] = -v.y / mol->mview->dimension;
8782 f[2] = -v.z / mol->mview->dimension;
8783 TrackballSetTranslate(mol->mview->track, f);
8784 MainViewCallback_setNeedsDisplay(mol->mview, 1);
8790 * set_background_color(red, green, blue)
8792 * Set the background color of the model window.
8795 s_Molecule_SetBackgroundColor(int argc, VALUE *argv, VALUE self)
8798 Data_Get_Struct(self, Molecule, mol);
8799 if (mol->mview != NULL) {
8800 VALUE rval, gval, bval;
8801 rb_scan_args(argc, argv, "30", &rval, &gval, &bval);
8802 MainView_setBackgroundColor(mol->mview, NUM2DBL(rb_Float(rval)), NUM2DBL(rb_Float(gval)), NUM2DBL(rb_Float(bval)));
8809 * create_graphic(kind, color, points, fill = nil) -> integer
8811 * Create a new graphic object.
8812 * kind: a symbol representing the kind of the graphic. :line, :poly, :cylinder, :cone, :ellipsoid
8813 * color: an array of 3 (rgb) or 4 (rgba) floating numbers
8814 * points: an array of Vectors
8818 s_Molecule_CreateGraphic(int argc, VALUE *argv, VALUE self)
8824 VALUE kval, cval, pval, fval;
8825 Data_Get_Struct(self, Molecule, mol);
8826 if (mol->mview == NULL)
8827 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
8828 rb_scan_args(argc, argv, "31", &kval, &cval, &pval, &fval);
8829 kval = rb_obj_as_string(kval);
8830 memset(&g, 0, sizeof(g));
8832 p = RSTRING_PTR(kval);
8833 if (strcmp(p, "line") == 0)
8834 g.kind = kMainViewGraphicLine;
8835 else if (strcmp(p, "poly") == 0)
8836 g.kind = kMainViewGraphicPoly;
8837 else if (strcmp(p, "cylinder") == 0)
8838 g.kind = kMainViewGraphicCylinder;
8839 else if (strcmp(p, "cone") == 0)
8840 g.kind = kMainViewGraphicCone;
8841 else if (strcmp(p, "ellipsoid") == 0)
8842 g.kind = kMainViewGraphicEllipsoid;
8843 else rb_raise(rb_eMolbyError, "unknown graphic object type: %s", p);
8844 g.closed = (RTEST(fval) ? 1 : 0);
8845 cval = rb_ary_to_ary(cval);
8846 n = RARRAY_LEN(cval);
8847 if (n < 3 || n >= 5)
8848 rb_raise(rb_eArgError, "the color should have 3 or 4 elements");
8851 for (i = 0; i < n; i++)
8852 g.rgba[i] = NUM2DBL(rb_Float(RARRAY_PTR(cval)[i]));
8853 pval = rb_ary_to_ary(pval);
8854 n = RARRAY_LEN(pval);
8855 ni = -1; /* If this is non-negative, then ni-th control point is [number, 0, 0] */
8857 rb_raise(rb_eArgError, "no control points are given");
8859 case kMainViewGraphicLine:
8861 rb_raise(rb_eArgError, "the line object must have at least two control points");
8863 case kMainViewGraphicPoly:
8865 rb_raise(rb_eArgError, "the polygon object must have at least three control points");
8867 case kMainViewGraphicCylinder:
8868 case kMainViewGraphicCone:
8870 rb_raise(rb_eArgError, "the %s object must have two control points and one number (radius)", (g.kind == kMainViewGraphicCylinder ? "cylinder" : "cone"));
8873 case kMainViewGraphicEllipsoid:
8877 rb_raise(rb_eArgError, "the ellipsoid object must have either one point and one number (radius) or four points (center and three main axes)");
8880 NewArray(&g.points, &g.npoints, sizeof(GLfloat) * 3, n);
8881 for (i = 0; i < n; i++) {
8884 v.x = NUM2DBL(rb_Float(RARRAY_PTR(pval)[i]));
8887 VectorFromValue(RARRAY_PTR(pval)[i], &v);
8889 g.points[i * 3] = v.x;
8890 g.points[i * 3 + 1] = v.y;
8891 g.points[i * 3 + 2] = v.z;
8893 if (g.kind == kMainViewGraphicEllipsoid && ni == 1) {
8895 AssignArray(&g.points, &g.npoints, sizeof(GLfloat) * 3, 4, NULL);
8896 g.points[6] = g.points[8] = g.points[9] = g.points[10] = 0;
8897 g.points[7] = g.points[11] = g.points[3];
8899 MainView_insertGraphic(mol->mview, -1, &g);
8900 return INT2NUM(mol->mview->ngraphics - 1);
8905 * remove_graphic(index) -> integer
8907 * Remove a graphic object.
8910 s_Molecule_RemoveGraphic(VALUE self, VALUE ival)
8914 Data_Get_Struct(self, Molecule, mol);
8915 if (mol->mview == NULL)
8916 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
8917 i = NUM2INT(rb_Integer(ival));
8918 if (i < 0 || i >= mol->mview->ngraphics)
8919 rb_raise(rb_eArgError, "graphic index is out of range");
8920 MainView_removeGraphic(mol->mview, i);
8926 * ngraphics -> integer
8928 * Get the number of graphic objects.
8931 s_Molecule_NGraphics(VALUE self)
8934 Data_Get_Struct(self, Molecule, mol);
8935 if (mol->mview == NULL)
8936 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
8937 return INT2NUM(mol->mview->ngraphics);
8942 * set_graphic_point(graphic_index, point_index, new_value) -> new_value
8944 * Change the point_index-th control point of graphic_index-th graphic object
8948 s_Molecule_SetGraphicPoint(VALUE self, VALUE gval, VALUE pval, VALUE nval)
8950 MainViewGraphic *gp;
8954 Data_Get_Struct(self, Molecule, mol);
8955 if (mol->mview == NULL)
8956 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
8957 index = NUM2INT(rb_Integer(gval));
8958 if (index < 0 || index >= mol->mview->ngraphics)
8959 rb_raise(rb_eArgError, "the graphic index is out of range");
8960 gp = mol->mview->graphics + index;
8961 index = NUM2INT(rb_Integer(pval));
8962 if (index < 0 || index >= gp->npoints)
8963 rb_raise(rb_eArgError, "the point index is out of range");
8964 if (rb_obj_is_kind_of(nval, rb_cNumeric)) {
8965 if ((gp->kind == kMainViewGraphicCylinder || gp->kind == kMainViewGraphicCone) && index == 2) {
8966 v.x = NUM2DBL(rb_Float(nval));
8968 } else if (gp->kind == kMainViewGraphicEllipsoid && index == 1) {
8969 gp->points[3] = gp->points[7] = gp->points[11] = NUM2DBL(rb_Float(nval));
8970 gp->points[4] = gp->points[5] = gp->points[6] = gp->points[8] = gp->points[9] = gp->points[10] = 0;
8972 } else rb_raise(rb_eArgError, "the argument must be an array-like object");
8975 v.x = kInvalidFloat;
8977 } else VectorFromValue(nval, &v);
8979 gp->points[index * 3] = v.x;
8980 gp->points[index * 3 + 1] = v.y;
8981 gp->points[index * 3 + 2] = v.z;
8982 MoleculeCallback_notifyModification(mol, 0);
8988 * set_graphic_color(graphic_index, new_value) -> new_value
8990 * Change the color of graphic_index-th graphic object
8994 s_Molecule_SetGraphicColor(VALUE self, VALUE gval, VALUE cval)
8996 MainViewGraphic *gp;
8999 Data_Get_Struct(self, Molecule, mol);
9000 if (mol->mview == NULL)
9001 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9002 index = NUM2INT(rb_Integer(gval));
9003 if (index < 0 || index >= mol->mview->ngraphics)
9004 rb_raise(rb_eArgError, "the graphic index is out of range");
9005 gp = mol->mview->graphics + index;
9006 cval = rb_ary_to_ary(cval);
9007 n = RARRAY_LEN(cval);
9008 if (n != 3 && n != 4)
9009 rb_raise(rb_eArgError, "the color argument must have 3 or 4 numbers");
9010 for (index = 0; index < n; index++) {
9011 gp->rgba[index] = NUM2DBL(rb_Float(RARRAY_PTR(cval)[index]));
9015 MoleculeCallback_notifyModification(mol, 0);
9021 * show_graphic(graphic_index) -> self
9023 * Enable the visible flag of the graphic_index-th graphic object
9027 s_Molecule_ShowGraphic(VALUE self, VALUE gval)
9029 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;
9040 MoleculeCallback_notifyModification(mol, 0);
9046 * hide_graphic(graphic_index) -> self
9048 * Disable the visible flag of the graphic_index-th graphic object
9052 s_Molecule_HideGraphic(VALUE self, VALUE gval)
9054 MainViewGraphic *gp;
9057 Data_Get_Struct(self, Molecule, mol);
9058 if (mol->mview == NULL)
9059 rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
9060 index = NUM2INT(rb_Integer(gval));
9061 if (index < 0 || index >= mol->mview->ngraphics)
9062 rb_raise(rb_eArgError, "the graphic index is out of range");
9063 gp = mol->mview->graphics + index;
9065 MoleculeCallback_notifyModification(mol, 0);
9073 * Show the string in the info text box.
9076 s_Molecule_ShowText(VALUE self, VALUE arg)
9079 Data_Get_Struct(self, Molecule, mol);
9080 if (mol->mview != NULL)
9081 MainViewCallback_drawInfoText(mol->mview, StringValuePtr(arg));
9087 * md_arena -> MDArena
9089 * Returns the MDArena object associated to this molecule. If no MDArena is associated to
9090 * this molecule, a new arena is created.
9093 s_Molecule_MDArena(VALUE self)
9097 Data_Get_Struct(self, Molecule, mol);
9098 if (mol->arena == NULL)
9100 retval = ValueFromMDArena(mol->arena);
9106 * set_parameter_attr(type, index, key, value, src) -> value
9108 * This method is used only internally.
9111 s_Molecule_SetParameterAttr(VALUE self, VALUE tval, VALUE ival, VALUE kval, VALUE vval, VALUE sval)
9113 /* This method is called from MolAction to change a MM parameter attribute. */
9118 Data_Get_Struct(self, Molecule, mol);
9119 pval = ValueFromMoleculeWithParameterTypeAndIndex(mol, FIX2INT(tval), NUM2INT(ival));
9120 vval = s_ParameterRef_SetAttr(pval, kval, vval);
9122 /* This is the special part of this method; it allows modification of the src field. */
9123 /* (ParameterRef#set_attr sets 0 to the src field) */
9124 Data_Get_Struct(pval, ParameterRef, pref);
9125 up = ParameterRefGetPar(pref);
9126 up->bond.src = FIX2INT(sval);
9133 * parameter -> Parameter
9135 * Get the local parameter of this molecule. If not defined, returns nil.
9138 s_Molecule_Parameter(VALUE self)
9141 Data_Get_Struct(self, Molecule, mol);
9142 /* if (mol->par == NULL)
9144 return s_NewParameterValueFromValue(self);
9149 * selectedMO -> IntGroup
9151 * Returns a group of selected mo in the "MO Info" table. If the MO info table
9152 * is not selected, returns nil. If the MO info table is selected but no MOs
9153 * are selected, returns an empty IntGroup. The numbers in the table are 1-based.
9156 s_Molecule_SelectedMO(VALUE self)
9161 Data_Get_Struct(self, Molecule, mol);
9162 if (mol->mview == NULL)
9164 ig = MainView_selectedMO(mol->mview);
9167 IntGroupOffset(ig, 1);
9168 val = ValueFromIntGroup(ig);
9169 IntGroupRelease(ig);
9175 * default_MO_grid(npoints = 80*80*80) -> [origin, dx, dy, dz, nx, ny, nz]
9177 * Returns a default MO grid for cube file generation. Origin: Vector, dx, dy, dz: float, nx, ny, nz: integer.
9178 * If the molecule does not contain a basis set information, then returns nil.
9181 s_Molecule_GetDefaultMOGrid(int argc, VALUE *argv, VALUE self)
9184 Vector o, dx, dy, dz;
9187 Int npoints = 80 * 80 * 80;
9188 Data_Get_Struct(self, Molecule, mol);
9189 if (mol->bset == NULL)
9191 rb_scan_args(argc, argv, "01", &nval);
9193 npoints = NUM2INT(rb_Integer(nval));
9194 if (MoleculeGetDefaultMOGrid(mol, npoints, &o, &dx, &dy, &dz, &nx, &ny, &nz) != 0)
9196 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));
9200 s_Cubegen_callback(double progress, void *ref)
9202 MyAppCallback_setProgressValue(progress);
9203 if (MyAppCallback_checkInterrupt())
9210 * cubegen(fname, mo, npoints=1000000 [, iflag [, beta]])
9211 * cubegen(fname, mo, origin, dx, dy, dz, nx, ny, nz [, iflag [, beta]])
9213 * Calculate the molecular orbital with number mo and create a 'cube' file.
9214 * In the first form, the cube size is estimated from the atomic coordinates. In the
9215 * second form, the cube dimension is explicitly given.
9216 * Returns fname when successful, nil otherwise.
9217 * If iflag is non-false, then MyAppCallback_checkInterrupt() is periodically called during calculation.
9218 * If beta is non-false, then the beta MO is calculated (valid only for UHF MO)
9219 * (The interrupt monitoring thread is disabled, so as not to enter Ruby interpreter during calculation)
9222 s_Molecule_Cubegen(int argc, VALUE *argv, VALUE self)
9224 VALUE fval, mval, oval, dxval, dyval, dzval, nxval, nyval, nzval, ival, bval;
9226 Int mono, nx, ny, nz, npoints;
9227 Vector o, dx, dy, dz;
9230 Data_Get_Struct(self, Molecule, mol);
9231 if (mol->bset == NULL)
9232 rb_raise(rb_eMolbyError, "The molecule does not contain MO information");
9233 rb_scan_args(argc, argv, "29", &fval, &mval, &oval, &dxval, &dyval, &dzval, &nxval, &nyval, &nzval, &ival, &bval);
9235 /* Set up parameters */
9236 mono = NUM2INT(rb_Integer(mval));
9237 if (mono <= 0 || mono > mol->bset->ncomps)
9238 rb_raise(rb_eMolbyError, "The MO number (%d) is out of range (should be 1..%d)", mono, mol->bset->ncomps);
9240 if (mol->bset->rflag != 0)
9241 rb_raise(rb_eMolbyError, "Beta MO is requested but not present");
9242 mono += mol->bset->ncomps;
9245 if (oval == Qnil || dxval == Qnil || dyval == Qnil) {
9246 /* Automatic grid formation */
9248 npoints = NUM2INT(rb_Integer(oval));
9252 else if (npoints < 8)
9253 rb_raise(rb_eMolbyError, "The number of points (%d) should be at least 8", npoints);
9254 if (MoleculeGetDefaultMOGrid(mol, npoints, &o, &dx, &dy, &dz, &nx, &ny, &nz) != 0)
9255 rb_raise(rb_eMolbyError, "Cannot determine cube grids");
9259 VectorFromValue(oval, &o);
9260 if (TYPE(dxval) == T_ARRAY || rb_obj_is_kind_of(dxval, rb_cVector3D))
9261 VectorFromValue(dxval, &dx);
9263 dx.x = NUM2DBL(rb_Float(dxval));
9266 if (TYPE(dyval) == T_ARRAY || rb_obj_is_kind_of(dyval, rb_cVector3D))
9267 VectorFromValue(dyval, &dy);
9269 dy.y = NUM2DBL(rb_Float(dyval));
9272 if (TYPE(dzval) == T_ARRAY || rb_obj_is_kind_of(dzval, rb_cVector3D))
9273 VectorFromValue(dzval, &dz);
9275 dz.z = NUM2DBL(rb_Float(dzval));
9278 nx = NUM2INT(rb_Integer(nxval));
9279 ny = NUM2INT(rb_Integer(nyval));
9280 nz = NUM2INT(rb_Integer(nzval));
9281 if (nx <= 0 || ny <= 0 || nz <= 0)
9282 rb_raise(rb_eMolbyError, "The number of points (%d,%d,%d) should be positive integers", nx, ny, nz);
9283 else if (nx > 10000 || ny > 10000 || nz > 10000 || nx * ny * nz > 100000000)
9284 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);
9288 index = MoleculeCalcMO(mol, mono, &o, &dx, &dy, &dz, nx, ny, nz, (RTEST(ival) ? s_Cubegen_callback : NULL), NULL);
9292 rb_raise(rb_eMolbyError, "Cannot calculate MO %d", mono);
9294 /* Output to file */
9295 MoleculeCallback_displayName(mol, buf, sizeof buf);
9296 n = MoleculeOutputCube(mol, index, FileStringValuePtr(fval), buf);
9298 rb_raise(rb_eMolbyError, "Cannot output MO cube to file %p", FileStringValuePtr(fval));
9300 /* Discard the cube */
9301 MoleculeClearCubeAtIndex(mol, index);
9309 * Get the number of electrostatic potential info.
9312 s_Molecule_NElpots(VALUE self)
9315 Data_Get_Struct(self, Molecule, mol);
9316 return INT2NUM(mol->nelpots);
9323 * Get the electrostatic potential info at the given index. If present, then the
9324 * return value is [Vector, Float] (position and potential). If not present, then
9328 s_Molecule_Elpot(VALUE self, VALUE ival)
9332 Data_Get_Struct(self, Molecule, mol);
9333 idx = NUM2INT(rb_Integer(ival));
9334 if (idx < 0 || idx >= mol->nelpots)
9336 return rb_ary_new3(2, ValueFromVector(&mol->elpots[idx].pos), rb_float_new(mol->elpots[idx].esp));
9341 * add_gaussian_orbital_shell(sym, nprims, atom_index)
9343 * To be used internally. Add a gaussian orbital shell with symmetry code, number of primitives,
9344 * and the corresponding atom index. Symmetry code: 0, S-type; 1, P-type; -1, SP-type; 2, D-type;
9348 s_Molecule_AddGaussianOrbitalShell(VALUE self, VALUE symval, VALUE npval, VALUE aval)
9351 int sym, nprims, a_idx, n;
9352 Data_Get_Struct(self, Molecule, mol);
9353 sym = NUM2INT(rb_Integer(symval));
9354 nprims = NUM2INT(rb_Integer(npval));
9355 a_idx = NUM2INT(rb_Integer(aval));
9356 n = MoleculeAddGaussianOrbitalShell(mol, sym, nprims, a_idx);
9358 rb_raise(rb_eMolbyError, "Molecule is emptry");
9360 rb_raise(rb_eMolbyError, "Low memory");
9362 rb_raise(rb_eMolbyError, "Unknown orbital type");
9364 rb_raise(rb_eMolbyError, "Unknown error");
9370 * add_gaussian_primitive_coefficients(exponent, contraction, contraction_sp)
9372 * To be used internally. Add a gaussian primitive coefficients.
9375 s_Molecule_AddGaussianPrimitiveCoefficients(VALUE self, VALUE expval, VALUE cval, VALUE cspval)
9379 Double exponent, contraction, contraction_sp;
9380 Data_Get_Struct(self, Molecule, mol);
9381 exponent = NUM2DBL(rb_Float(expval));
9382 contraction = NUM2DBL(rb_Float(cval));
9383 contraction_sp = NUM2DBL(rb_Float(cspval));
9384 n = MoleculeAddGaussianPrimitiveCoefficients(mol, exponent, contraction, contraction_sp);
9386 rb_raise(rb_eMolbyError, "Molecule is emptry");
9388 rb_raise(rb_eMolbyError, "Low memory");
9390 rb_raise(rb_eMolbyError, "Unknown error");
9398 * Returns either "RHF", "UHF", or "ROHF". If no MO info is present, returns nil.
9401 s_Molecule_MOType(VALUE self)
9404 Data_Get_Struct(self, Molecule, mol);
9405 if (mol != NULL && mol->bset != NULL) {
9407 int rflag = mol->bset->rflag;
9410 else if (rflag == 2)
9413 return rb_str_new2(s);
9419 * set_mo_coefficients(idx, energy, coefficients)
9421 * To be used internally. Add a MO coefficients. Idx is the MO index (for open shell system,
9422 * beta MOs comes after all alpha MOs), energy is the MO energy, coefficients is an array
9423 * of MO coefficients.
9426 s_Molecule_SetMOCoefficients(VALUE self, VALUE ival, VALUE eval, VALUE aval)
9432 Data_Get_Struct(self, Molecule, mol);
9433 idx = NUM2INT(rb_Integer(ival));
9434 energy = NUM2DBL(rb_Float(eval));
9435 aval = rb_ary_to_ary(aval);
9436 ncomps = RARRAY_LEN(aval);
9437 coeffs = (Double *)calloc(sizeof(Double), ncomps);
9438 if (coeffs == NULL) {
9442 for (i = 0; i < ncomps; i++)
9443 coeffs[i] = NUM2DBL(rb_Float(RARRAY_PTR(aval)[i]));
9444 i = MoleculeSetMOCoefficients(mol, idx, energy, ncomps, coeffs);
9447 rb_raise(rb_eMolbyError, "Molecule is emptry");
9449 rb_raise(rb_eMolbyError, "Low memory");
9451 rb_raise(rb_eMolbyError, "Bad or inconsistent number of MOs");
9453 rb_raise(rb_eMolbyError, "Bad MO index");
9455 rb_raise(rb_eMolbyError, "Insufficient number of coefficients are given");
9457 rb_raise(rb_eMolbyError, "Unknown error");
9463 * allocate_basis_set_record(rflag, ne_alpha, ne_beta)
9465 * To be used internally. Allocate a basis set record. rflag: 0, unrestricted; 1, restricted.
9466 * ne_alpha, ne_beta: number of alpha/beta electrons.
9469 s_Molecule_AllocateBasisSetRecord(VALUE self, VALUE rval, VALUE naval, VALUE nbval)
9472 Int rflag, na, nb, n;
9473 Data_Get_Struct(self, Molecule, mol);
9474 rflag = NUM2INT(rb_Integer(rval));
9475 na = NUM2INT(rb_Integer(naval));
9476 nb = NUM2INT(rb_Integer(nbval));
9477 n = MoleculeAllocateBasisSetRecord(mol, rflag, na, nb);
9479 rb_raise(rb_eMolbyError, "Molecule is emptry");
9481 rb_raise(rb_eMolbyError, "Low memory");
9483 rb_raise(rb_eMolbyError, "Unknown error");
9489 * search_equivalent_atoms(ig = nil)
9491 * Search equivalent atoms (within the atom group if given). Returns an array of integers.
9494 s_Molecule_SearchEquivalentAtoms(int argc, VALUE *argv, VALUE self)
9500 Data_Get_Struct(self, Molecule, mol);
9501 if (mol->natoms == 0)
9503 rb_scan_args(argc, argv, "01", &val);
9505 ig = IntGroupFromValue(val);
9507 result = MoleculeSearchEquivalentAtoms(mol, ig);
9509 rb_raise(rb_eMolbyError, "Failed to search equivalent atoms (out of memory?)");
9511 IntGroupRelease(ig);
9512 val = rb_ary_new2(mol->natoms);
9513 for (i = 0; i < mol->natoms; i++)
9514 rb_ary_push(val, INT2NUM(result[i]));
9521 * create_pi_anchor(name, group [, type] [, weights] [, index]) -> AtomRef
9523 * Create a pi anchor, which is a "dummy" atom to represent pi-metal bonds.
9524 * Name is the name of the new pi anchor, and group is the atoms that define
9525 * the pi system. Type (a String) is an atom type for MM implementation.
9526 * Weights is the relative weights of the component atoms; if omitted, then
9527 * 1.0/n (n is the number of component atoms) is assumed for all atoms.
9528 * The weight values will be normalized so that the sum of the weights is 1.0.
9529 * The weight values must be positive.
9530 * Index is the atom index where the created pi-anchor is inserted in the
9531 * atoms array; if omitted, the pi-anchor is inserted after the component atom
9532 * having the largest index.
9535 s_Molecule_CreatePiAnchor(int argc, VALUE *argv, VALUE self)
9540 Int i, n, idx, last_component;
9544 if (argc < 2 || argc >= 6)
9545 rb_raise(rb_eMolbyError, "too %s arguments (should be 2..5)", (argc < 2 ? "few" : "many"));
9549 Data_Get_Struct(self, Molecule, mol);
9550 ig = IntGroupFromValue(gval);
9551 memset(&a, 0, sizeof(a));
9552 memset(&an, 0, sizeof(an));
9553 strncpy(a.aname, StringValuePtr(nval), 4);
9554 if (a.aname[0] == '_')
9555 rb_raise(rb_eMolbyError, "please avoid a name beginning with '_' for a pi anchor, because it causes some internal confusion.");
9556 a.type = AtomTypeEncodeToUInt("##"); /* Default atom type for pi_anchor */
9557 for (i = 0; (n = IntGroupGetNthPoint(ig, i)) >= 0; i++) {
9558 if (n >= mol->natoms) {
9559 AtomConnectResize(&an.connect, 0);
9560 rb_raise(rb_eMolbyError, "atom index (%d) out of range", n);
9562 AtomConnectInsertEntry(&an.connect, an.connect.count, n);
9565 if (an.connect.count == 0)
9566 rb_raise(rb_eMolbyError, "no atoms are specified");
9567 NewArray(&an.coeffs, &an.ncoeffs, sizeof(Double), an.connect.count);
9568 for (i = 0; i < an.connect.count; i++) {
9569 an.coeffs[i] = 1.0 / an.connect.count;
9571 if (argc > 0 && (argv[0] == Qnil || rb_obj_is_kind_of(argv[0], rb_cString))) {
9573 if (argv[0] != Qnil)
9574 a.type = AtomTypeEncodeToUInt(StringValuePtr(argv[0]));
9578 if (argc > 0 && (argv[0] == Qnil || rb_obj_is_kind_of(argv[0], rb_mEnumerable))) {
9579 if (argv[0] != Qnil) {
9580 VALUE aval = rb_ary_to_ary(argv[0]);
9582 if (RARRAY_LEN(aval) != an.connect.count)
9583 rb_raise(rb_eMolbyError, "the number of weight values does not match the number of atoms");
9584 for (i = 0, sum = 0.0; i < an.connect.count; i++) {
9585 d = NUM2DBL(rb_Float(RARRAY_PTR(aval)[i]));
9587 rb_raise(rb_eMolbyError, "the weight value must be positive");
9591 for (i = 0; i < an.connect.count; i++)
9592 an.coeffs[i] /= sum;
9597 if (argc > 0 && argv[0] != Qnil) {
9599 idx = NUM2INT(rb_Integer(argv[0]));
9601 if (idx < 0 || idx > mol->natoms) {
9602 /* Immediately after the last specified atom */
9603 idx = last_component + 1;
9605 a.anchor = (PiAnchor *)malloc(sizeof(PiAnchor));
9606 memmove(a.anchor, &an, sizeof(PiAnchor));
9607 /* Use residue information of the last specified atom */
9608 ap = ATOM_AT_INDEX(mol->atoms, last_component);
9609 a.resSeq = ap->resSeq;
9610 strncpy(a.resName, ap->resName, 4);
9611 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &a, idx, &idx) != 0)
9613 MoleculeCalculatePiAnchorPosition(mol, idx);
9614 aref = AtomRefNew(mol, idx);
9615 return Data_Wrap_Struct(rb_cAtomRef, 0, (void (*)(void *))AtomRefRelease, aref);
9620 * current -> Molecule
9622 * Get the currently "active" molecule.
9625 s_Molecule_Current(VALUE klass)
9627 return ValueFromMolecule(MoleculeCallback_currentMolecule());
9632 * Molecule[] -> Molecule
9633 * Molecule[n] -> Molecule
9634 * Molecule[name] -> Molecule
9635 * Molecule[name, k] -> Molecule
9636 * Molecule[regex] -> Molecule
9637 * Molecule[regex, k] -> Molecule
9639 * Molecule[] is equivalent to Molecule.current.
9640 * Molecule[n] (n is an integer) is equivalent to Molecule.list[n].
9641 * Molecule[name] gives the first document (in the order of creation time) that has
9642 * the given name. If a second argument (k) is given, the k-th document that has the
9643 * given name is returned.
9644 * Molecule[regex] gives the first document (in the order of creation time) that
9645 * has a name matching the regular expression. If a second argument (k) is given,
9646 * the k-th document that has a name matching the re is returned.
9649 s_Molecule_MoleculeAtIndex(int argc, VALUE *argv, VALUE klass)
9655 rb_scan_args(argc, argv, "02", &val, &kval);
9657 return s_Molecule_Current(klass);
9658 if (rb_obj_is_kind_of(val, rb_cInteger)) {
9660 mol = MoleculeCallback_moleculeAtIndex(idx);
9661 } else if (rb_obj_is_kind_of(val, rb_cString)) {
9662 char *p = StringValuePtr(val);
9663 k = (kval == Qnil ? 1 : NUM2INT(rb_Integer(kval)));
9664 for (idx = 0; (mol = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
9665 MoleculeCallback_displayName(mol, buf, sizeof buf);
9666 if (strcmp(buf, p) == 0 && --k == 0)
9669 } else if (rb_obj_is_kind_of(val, rb_cRegexp)) {
9670 k = (kval == Qnil ? 1 : NUM2INT(rb_Integer(kval)));
9671 for (idx = 0; (mol = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
9673 MoleculeCallback_displayName(mol, buf, sizeof buf);
9674 name = rb_str_new2(buf);
9675 if (rb_reg_match(val, name) != Qnil && --k == 0)
9678 } else rb_raise(rb_eTypeError, "the argument should be either empty, an integer, a string, or a regular expression");
9682 else return ValueFromMolecule(mol);
9687 * list -> array of Molecules
9689 * Get the list of molecules associated to the documents, in the order of creation
9690 * time of the document. If no document is open, returns an empry array.
9693 s_Molecule_List(VALUE klass)
9700 while ((mol = MoleculeCallback_moleculeAtIndex(i)) != NULL) {
9701 rb_ary_push(ary, ValueFromMolecule(mol));
9709 * ordered_list -> array of Molecules
9711 * Get the list of molecules associated to the documents, in the order of front-to-back
9712 * ordering of the associated window. If no document is open, returns an empry array.
9715 s_Molecule_OrderedList(VALUE klass)
9722 while ((mol = MoleculeCallback_moleculeAtOrderedIndex(i)) != NULL) {
9723 rb_ary_push(ary, ValueFromMolecule(mol));
9731 * error_message -> String
9733 * Get the error_message from the last load/save method. If no error, returns nil.
9736 s_Molecule_ErrorMessage(VALUE klass)
9738 if (gLoadSaveErrorMessage == NULL)
9740 else return rb_str_new2(gLoadSaveErrorMessage);
9745 * set_error_message(String)
9746 * Molecule.error_message = String
9748 * Get the error_message from the last load/save method. If no error, returns nil.
9751 s_Molecule_SetErrorMessage(VALUE klass, VALUE sval)
9753 if (gLoadSaveErrorMessage != NULL) {
9754 free(gLoadSaveErrorMessage);
9755 gLoadSaveErrorMessage = NULL;
9758 sval = rb_str_to_str(sval);
9759 gLoadSaveErrorMessage = strdup(StringValuePtr(sval));
9769 /* Define module Molby */
9770 rb_mMolby = rb_define_module("Molby");
9772 /* Define Vector3D, Transform, IntGroup */
9775 /* Define MDArena */
9776 Init_MolbyMDTypes();
9778 /* class Molecule */
9779 rb_cMolecule = rb_define_class_under(rb_mMolby, "Molecule", rb_cObject);
9780 rb_define_alloc_func(rb_cMolecule, s_Molecule_Alloc);
9781 rb_define_private_method(rb_cMolecule, "initialize", s_Molecule_Initialize, -1);
9782 rb_define_private_method(rb_cMolecule, "initialize_copy", s_Molecule_InitCopy, 1);
9783 rb_define_method(rb_cMolecule, "loadmbsf", s_Molecule_Loadmbsf, -1);
9784 rb_define_method(rb_cMolecule, "loadpsf", s_Molecule_Loadpsf, -1);
9785 rb_define_alias(rb_cMolecule, "loadpsfx", "loadpsf");
9786 rb_define_method(rb_cMolecule, "loadpdb", s_Molecule_Loadpdb, -1);
9787 rb_define_method(rb_cMolecule, "loaddcd", s_Molecule_Loaddcd, -1);
9788 rb_define_method(rb_cMolecule, "loadtep", s_Molecule_Loadtep, -1);
9789 rb_define_method(rb_cMolecule, "loadres", s_Molecule_Loadres, -1);
9790 rb_define_method(rb_cMolecule, "loadfchk", s_Molecule_Loadfchk, -1);
9791 rb_define_alias(rb_cMolecule, "loadfch", "loadfchk");
9792 rb_define_method(rb_cMolecule, "loaddat", s_Molecule_Loaddat, -1);
9793 rb_define_method(rb_cMolecule, "molload", s_Molecule_Load, -1);
9794 rb_define_method(rb_cMolecule, "molsave", s_Molecule_Save, -1);
9795 rb_define_method(rb_cMolecule, "savembsf", s_Molecule_Savembsf, 1);
9796 rb_define_method(rb_cMolecule, "savepsf", s_Molecule_Savepsf, 1);
9797 rb_define_alias(rb_cMolecule, "savepsfx", "savepsf");
9798 rb_define_method(rb_cMolecule, "savepdb", s_Molecule_Savepdb, 1);
9799 rb_define_method(rb_cMolecule, "savedcd", s_Molecule_Savedcd, 1);
9800 /* rb_define_method(rb_cMolecule, "savetep", s_Molecule_Savetep, 1); */
9801 rb_define_method(rb_cMolecule, "name", s_Molecule_Name, 0);
9802 rb_define_method(rb_cMolecule, "set_name", s_Molecule_SetName, 1);
9803 rb_define_method(rb_cMolecule, "path", s_Molecule_Path, 0);
9804 rb_define_method(rb_cMolecule, "dir", s_Molecule_Dir, 0);
9805 rb_define_method(rb_cMolecule, "inspect", s_Molecule_Inspect, 0);
9806 rb_define_method(rb_cMolecule, "atoms", s_Molecule_Atoms, 0);
9807 rb_define_method(rb_cMolecule, "bonds", s_Molecule_Bonds, 0);
9808 rb_define_method(rb_cMolecule, "angles", s_Molecule_Angles, 0);
9809 rb_define_method(rb_cMolecule, "dihedrals", s_Molecule_Dihedrals, 0);
9810 rb_define_method(rb_cMolecule, "impropers", s_Molecule_Impropers, 0);
9811 rb_define_method(rb_cMolecule, "residues", s_Molecule_Residues, 0);
9812 rb_define_method(rb_cMolecule, "natoms", s_Molecule_Natoms, 0);
9813 rb_define_method(rb_cMolecule, "nbonds", s_Molecule_Nbonds, 0);
9814 rb_define_method(rb_cMolecule, "nangles", s_Molecule_Nangles, 0);
9815 rb_define_method(rb_cMolecule, "ndihedrals", s_Molecule_Ndihedrals, 0);
9816 rb_define_method(rb_cMolecule, "nimpropers", s_Molecule_Nimpropers, 0);
9818 rb_define_method(rb_cMolecule, "bond_par", s_Molecule_BondParIsObsolete, 1);
9819 rb_define_method(rb_cMolecule, "angle_par", s_Molecule_BondParIsObsolete, 1);
9820 rb_define_method(rb_cMolecule, "dihedral_par", s_Molecule_BondParIsObsolete, 1);
9821 rb_define_method(rb_cMolecule, "improper_par", s_Molecule_BondParIsObsolete, 1);
9822 rb_define_method(rb_cMolecule, "vdw_par", s_Molecule_BondParIsObsolete, 1);
9824 rb_define_method(rb_cMolecule, "start_step", s_Molecule_StartStep, 0);
9825 rb_define_method(rb_cMolecule, "start_step=", s_Molecule_SetStartStep, 1);
9826 rb_define_method(rb_cMolecule, "steps_per_frame", s_Molecule_StepsPerFrame, 0);
9827 rb_define_method(rb_cMolecule, "steps_per_frame=", s_Molecule_SetStepsPerFrame, 1);
9828 rb_define_method(rb_cMolecule, "ps_per_step", s_Molecule_PsPerStep, 0);
9829 rb_define_method(rb_cMolecule, "ps_per_step=", s_Molecule_SetPsPerStep, 1);
9831 rb_define_method(rb_cMolecule, "nresidues", s_Molecule_Nresidues, 0);
9832 rb_define_method(rb_cMolecule, "nresidues=", s_Molecule_ChangeNresidues, 1);
9833 rb_define_method(rb_cMolecule, "max_residue_number", s_Molecule_MaxResSeq, -1);
9834 rb_define_method(rb_cMolecule, "min_residue_number", s_Molecule_MinResSeq, -1);
9835 rb_define_method(rb_cMolecule, "each_atom", s_Molecule_EachAtom, -1);
9836 rb_define_method(rb_cMolecule, "cell", s_Molecule_Cell, 0);
9837 rb_define_method(rb_cMolecule, "cell=", s_Molecule_SetCell, -1);
9838 rb_define_alias(rb_cMolecule, "set_cell", "cell=");
9839 rb_define_method(rb_cMolecule, "box", s_Molecule_Box, 0);
9840 rb_define_method(rb_cMolecule, "box=", s_Molecule_SetBox, 1);
9841 rb_define_method(rb_cMolecule, "set_box", s_Molecule_SetBox, -2);
9842 rb_define_method(rb_cMolecule, "cell_transform", s_Molecule_CellTransform, 0);
9843 rb_define_method(rb_cMolecule, "cell_periodicity", s_Molecule_CellPeriodicity, 0);
9844 rb_define_method(rb_cMolecule, "cell_periodicity=", s_Molecule_SetCellPeriodicity, 1);
9845 rb_define_alias(rb_cMolecule, "set_cell_periodicity", "cell_periodicity=");
9846 rb_define_method(rb_cMolecule, "cell_flexibility", s_Molecule_CellFlexibility, 0);
9847 rb_define_method(rb_cMolecule, "cell_flexibility=", s_Molecule_SetCellFlexibility, 1);
9848 rb_define_alias(rb_cMolecule, "set_cell_flexibility", "cell_flexibility=");
9849 rb_define_method(rb_cMolecule, "symmetry", s_Molecule_Symmetry, 0);
9850 rb_define_alias(rb_cMolecule, "symmetries", "symmetry");
9851 rb_define_method(rb_cMolecule, "nsymmetries", s_Molecule_Nsymmetries, 0);
9852 rb_define_method(rb_cMolecule, "add_symmetry", s_Molecule_AddSymmetry, 1);
9853 rb_define_method(rb_cMolecule, "remove_symmetry", s_Molecule_RemoveSymmetry, -1);
9854 rb_define_alias(rb_cMolecule, "remove_symmetries", "remove_symmetry");
9855 rb_define_method(rb_cMolecule, "extract", s_Molecule_Extract, -1);
9856 rb_define_method(rb_cMolecule, "add", s_Molecule_Add, 1);
9857 rb_define_alias(rb_cMolecule, "+", "add");
9858 rb_define_method(rb_cMolecule, "remove", s_Molecule_Remove, 1);
9859 rb_define_method(rb_cMolecule, "atom_group", s_Molecule_AtomGroup, -1);
9860 rb_define_method(rb_cMolecule, "atom_index", s_Molecule_AtomIndex, 1);
9861 rb_define_method(rb_cMolecule, "create_atom", s_Molecule_CreateAnAtom, -1);
9862 rb_define_method(rb_cMolecule, "duplicate_atom", s_Molecule_DuplicateAnAtom, -1);
9863 rb_define_method(rb_cMolecule, "create_bond", s_Molecule_CreateBond, -1);
9864 rb_define_alias(rb_cMolecule, "create_bonds", "create_bond");
9865 rb_define_method(rb_cMolecule, "remove_bond", s_Molecule_RemoveBond, -1);
9866 rb_define_alias(rb_cMolecule, "remove_bonds", "remove_bond");
9867 rb_define_method(rb_cMolecule, "add_angle", s_Molecule_AddAngle, 3);
9868 rb_define_method(rb_cMolecule, "remove_angle", s_Molecule_RemoveAngle, 3);
9869 rb_define_method(rb_cMolecule, "add_dihedral", s_Molecule_AddDihedral, 4);
9870 rb_define_method(rb_cMolecule, "remove_dihedral", s_Molecule_RemoveDihedral, 4);
9871 rb_define_method(rb_cMolecule, "add_improper", s_Molecule_AddImproper, 4);
9872 rb_define_method(rb_cMolecule, "remove_improper", s_Molecule_RemoveImproper, 4);
9873 rb_define_method(rb_cMolecule, "assign_residue", s_Molecule_AssignResidue, 2);
9874 rb_define_method(rb_cMolecule, "offset_residue", s_Molecule_OffsetResidue, 2);
9875 rb_define_method(rb_cMolecule, "renumber_atoms", s_Molecule_RenumberAtoms, 1);
9876 rb_define_method(rb_cMolecule, "find_close_atoms", s_Molecule_FindCloseAtoms, -1);
9877 rb_define_method(rb_cMolecule, "guess_bonds", s_Molecule_GuessBonds, -1);
9878 rb_define_method(rb_cMolecule, "selection", s_Molecule_Selection, 0);
9879 rb_define_method(rb_cMolecule, "selection=", s_Molecule_SetSelection, 1);
9880 rb_define_method(rb_cMolecule, "set_undoable_selection", s_Molecule_SetUndoableSelection, 1);
9881 rb_define_method(rb_cMolecule, "hidden_atoms", s_Molecule_HiddenAtoms, 0); /* obsolete */
9882 rb_define_method(rb_cMolecule, "hidden_atoms=", s_Molecule_SetHiddenAtoms, 1); /* obsolete */
9883 rb_define_alias(rb_cMolecule, "set_hidden_atoms", "hidden_atoms="); /* obsolete */
9884 rb_define_method(rb_cMolecule, "frame", s_Molecule_Frame, 0);
9885 rb_define_method(rb_cMolecule, "frame=", s_Molecule_SelectFrame, 1);
9886 rb_define_alias(rb_cMolecule, "select_frame", "frame=");
9887 rb_define_method(rb_cMolecule, "nframes", s_Molecule_Nframes, 0);
9888 rb_define_method(rb_cMolecule, "create_frame", s_Molecule_CreateFrames, -1);
9889 rb_define_method(rb_cMolecule, "insert_frame", s_Molecule_InsertFrames, -1);
9890 rb_define_method(rb_cMolecule, "remove_frame", s_Molecule_RemoveFrames, -1);
9891 rb_define_alias(rb_cMolecule, "create_frames", "create_frame");
9892 rb_define_alias(rb_cMolecule, "insert_frames", "insert_frame");
9893 rb_define_alias(rb_cMolecule, "remove_frames", "remove_frame");
9894 rb_define_method(rb_cMolecule, "each_frame", s_Molecule_EachFrame, 0);
9895 rb_define_method(rb_cMolecule, "get_coord_from_frame", s_Molecule_GetCoordFromFrame, -1);
9896 rb_define_method(rb_cMolecule, "register_undo", s_Molecule_RegisterUndo, -1);
9897 rb_define_method(rb_cMolecule, "undo_enabled?", s_Molecule_UndoEnabled, 0);
9898 rb_define_method(rb_cMolecule, "undo_enabled=", s_Molecule_SetUndoEnabled, 1);
9899 rb_define_method(rb_cMolecule, "set_atom_attr", s_Molecule_SetAtomAttr, 3);
9900 rb_define_method(rb_cMolecule, "get_atom_attr", s_Molecule_GetAtomAttr, 2);
9901 rb_define_method(rb_cMolecule, "fragment", s_Molecule_Fragment, -1);
9902 rb_define_method(rb_cMolecule, "each_fragment", s_Molecule_EachFragment, 0);
9903 rb_define_method(rb_cMolecule, "detachable?", s_Molecule_Detachable_P, 1);
9904 rb_define_method(rb_cMolecule, "bonds_on_border", s_Molecule_BondsOnBorder, -1);
9905 rb_define_method(rb_cMolecule, "translate", s_Molecule_Translate, -1);
9906 rb_define_method(rb_cMolecule, "rotate", s_Molecule_Rotate, -1);
9907 rb_define_method(rb_cMolecule, "reflect", s_Molecule_Reflect, -1);
9908 rb_define_method(rb_cMolecule, "invert", s_Molecule_Invert, -1);
9909 rb_define_method(rb_cMolecule, "transform", s_Molecule_Transform, -1);
9910 rb_define_method(rb_cMolecule, "center_of_mass", s_Molecule_CenterOfMass, -1);
9911 rb_define_method(rb_cMolecule, "centralize", s_Molecule_Centralize, -1);
9912 rb_define_method(rb_cMolecule, "bounds", s_Molecule_Bounds, -1);
9913 rb_define_method(rb_cMolecule, "measure_bond", s_Molecule_MeasureBond, 2);
9914 rb_define_method(rb_cMolecule, "measure_angle", s_Molecule_MeasureAngle, 3);
9915 rb_define_method(rb_cMolecule, "measure_dihedral", s_Molecule_MeasureDihedral, 4);
9916 rb_define_method(rb_cMolecule, "expand_by_symmetry", s_Molecule_ExpandBySymmetry, -1);
9917 rb_define_method(rb_cMolecule, "amend_by_symmetry", s_Molecule_AmendBySymmetry, -1);
9918 rb_define_method(rb_cMolecule, "transform_for_symop", s_Molecule_TransformForSymop, -1);
9919 rb_define_method(rb_cMolecule, "symop_for_transform", s_Molecule_SymopForTransform, -1);
9920 rb_define_method(rb_cMolecule, "wrap_unit_cell", s_Molecule_WrapUnitCell, 1);
9921 rb_define_method(rb_cMolecule, "find_conflicts", s_Molecule_FindConflicts, -1);
9922 rb_define_method(rb_cMolecule, "fit_coordinates", s_Molecule_FitCoordinates, -1);
9923 rb_define_method(rb_cMolecule, "display", s_Molecule_Display, 0);
9924 rb_define_method(rb_cMolecule, "make_front", s_Molecule_MakeFront, 0);
9925 rb_define_method(rb_cMolecule, "update_enabled?", s_Molecule_UpdateEnabled, 0);
9926 rb_define_method(rb_cMolecule, "update_enabled=", s_Molecule_SetUpdateEnabled, 1);
9927 rb_define_method(rb_cMolecule, "show_unitcell", s_Molecule_ShowUnitCell, -1);
9928 rb_define_method(rb_cMolecule, "show_hydrogens", s_Molecule_ShowHydrogens, -1);
9929 rb_define_method(rb_cMolecule, "show_hydrogens=", s_Molecule_ShowHydrogens, -1);
9930 rb_define_method(rb_cMolecule, "show_dummy_atoms", s_Molecule_ShowDummyAtoms, -1);
9931 rb_define_method(rb_cMolecule, "show_dummy_atoms=", s_Molecule_ShowDummyAtoms, -1);
9932 rb_define_method(rb_cMolecule, "show_expanded", s_Molecule_ShowExpanded, -1);
9933 rb_define_method(rb_cMolecule, "show_expanded=", s_Molecule_ShowExpanded, -1);
9934 rb_define_method(rb_cMolecule, "is_atom_visible", s_Molecule_IsAtomVisible, 1);
9935 rb_define_method(rb_cMolecule, "show_ellipsoids", s_Molecule_ShowEllipsoids, -1);
9936 rb_define_method(rb_cMolecule, "show_ellipsoids=", s_Molecule_ShowEllipsoids, -1);
9937 rb_define_method(rb_cMolecule, "show_graphite", s_Molecule_ShowGraphite, -1);
9938 rb_define_method(rb_cMolecule, "show_graphite=", s_Molecule_ShowGraphite, -1);
9939 rb_define_method(rb_cMolecule, "show_graphite?", s_Molecule_ShowGraphiteFlag, 0);
9940 rb_define_method(rb_cMolecule, "show_periodic_image", s_Molecule_ShowPeriodicImage, -1);
9941 rb_define_method(rb_cMolecule, "show_periodic_image=", s_Molecule_ShowPeriodicImage, -1);
9942 rb_define_method(rb_cMolecule, "show_periodic_image?", s_Molecule_ShowPeriodicImageFlag, 0);
9943 rb_define_alias(rb_cMolecule, "show_unitcell=", "show_unitcell");
9944 rb_define_alias(rb_cMolecule, "show_unit_cell", "show_unitcell");
9945 rb_define_alias(rb_cMolecule, "show_unit_cell=", "show_unitcell");
9946 rb_define_alias(rb_cMolecule, "show_hydrogens=", "show_hydrogens");
9947 rb_define_alias(rb_cMolecule, "show_dummy_atoms=", "show_dummy_atoms");
9948 rb_define_alias(rb_cMolecule, "show_expanded=", "show_expanded");
9949 rb_define_alias(rb_cMolecule, "show_ellipsoids=", "show_ellipsoids");
9950 rb_define_alias(rb_cMolecule, "show_graphite=", "show_graphite");
9951 rb_define_alias(rb_cMolecule, "show_periodic_image=", "show_periodic_image");
9952 rb_define_method(rb_cMolecule, "line_mode", s_Molecule_LineMode, -1);
9953 rb_define_alias(rb_cMolecule, "line_mode=", "line_mode");
9954 rb_define_method(rb_cMolecule, "resize_to_fit", s_Molecule_ResizeToFit, 0);
9955 #if 1 || !defined(__CMDMAC__)
9956 rb_define_method(rb_cMolecule, "get_view_rotation", s_Molecule_GetViewRotation, 0);
9957 rb_define_method(rb_cMolecule, "get_view_scale", s_Molecule_GetViewScale, 0);
9958 rb_define_method(rb_cMolecule, "get_view_center", s_Molecule_GetViewCenter, 0);
9959 rb_define_method(rb_cMolecule, "set_view_rotation", s_Molecule_SetViewRotation, 2);
9960 rb_define_method(rb_cMolecule, "set_view_scale", s_Molecule_SetViewScale, 1);
9961 rb_define_method(rb_cMolecule, "set_view_center", s_Molecule_SetViewCenter, 1);
9962 rb_define_method(rb_cMolecule, "set_background_color", s_Molecule_SetBackgroundColor, -1);
9963 rb_define_method(rb_cMolecule, "create_graphic", s_Molecule_CreateGraphic, -1);
9964 rb_define_method(rb_cMolecule, "remove_graphic", s_Molecule_RemoveGraphic, 1);
9965 rb_define_method(rb_cMolecule, "ngraphics", s_Molecule_NGraphics, 0);
9966 rb_define_method(rb_cMolecule, "set_graphic_point", s_Molecule_SetGraphicPoint, 3);
9967 rb_define_method(rb_cMolecule, "set_graphic_color", s_Molecule_SetGraphicColor, 2);
9968 rb_define_method(rb_cMolecule, "show_graphic", s_Molecule_ShowGraphic, 1);
9969 rb_define_method(rb_cMolecule, "hide_graphic", s_Molecule_HideGraphic, 1);
9971 rb_define_method(rb_cMolecule, "show_text", s_Molecule_ShowText, 1);
9972 rb_define_method(rb_cMolecule, "md_arena", s_Molecule_MDArena, 0);
9973 rb_define_method(rb_cMolecule, "set_parameter_attr", s_Molecule_SetParameterAttr, 5);
9974 rb_define_method(rb_cMolecule, "parameter", s_Molecule_Parameter, 0);
9975 rb_define_method(rb_cMolecule, "selected_MO", s_Molecule_SelectedMO, 0);
9976 rb_define_method(rb_cMolecule, "default_MO_grid", s_Molecule_GetDefaultMOGrid, -1);
9977 rb_define_method(rb_cMolecule, "cubegen", s_Molecule_Cubegen, -1);
9978 rb_define_method(rb_cMolecule, "nelpots", s_Molecule_NElpots, 0);
9979 rb_define_method(rb_cMolecule, "elpot", s_Molecule_Elpot, 1);
9980 rb_define_method(rb_cMolecule, "add_gaussian_orbital_shell", s_Molecule_AddGaussianOrbitalShell, 3);
9981 rb_define_method(rb_cMolecule, "add_gaussian_primitive_coefficients", s_Molecule_AddGaussianPrimitiveCoefficients, 3);
9982 rb_define_method(rb_cMolecule, "mo_type", s_Molecule_MOType, 0);
9983 rb_define_method(rb_cMolecule, "set_mo_coefficients", s_Molecule_SetMOCoefficients, 3);
9984 rb_define_method(rb_cMolecule, "allocate_basis_set_record", s_Molecule_AllocateBasisSetRecord, 3);
9985 rb_define_method(rb_cMolecule, "search_equivalent_atoms", s_Molecule_SearchEquivalentAtoms, -1);
9987 rb_define_method(rb_cMolecule, "create_pi_anchor", s_Molecule_CreatePiAnchor, -1);
9989 rb_define_singleton_method(rb_cMolecule, "current", s_Molecule_Current, 0);
9990 rb_define_singleton_method(rb_cMolecule, "[]", s_Molecule_MoleculeAtIndex, -1);
9991 rb_define_singleton_method(rb_cMolecule, "open", s_Molecule_Open, -1);
9992 rb_define_singleton_method(rb_cMolecule, "list", s_Molecule_List, 0);
9993 rb_define_singleton_method(rb_cMolecule, "ordered_list", s_Molecule_OrderedList, 0);
9994 rb_define_singleton_method(rb_cMolecule, "error_message", s_Molecule_ErrorMessage, 0);
9995 rb_define_singleton_method(rb_cMolecule, "set_error_message", s_Molecule_SetErrorMessage, 1);
9996 rb_define_singleton_method(rb_cMolecule, "error_message=", s_Molecule_SetErrorMessage, 1);
9998 /* class MolEnumerable */
9999 rb_cMolEnumerable = rb_define_class_under(rb_mMolby, "MolEnumerable", rb_cObject);
10000 rb_include_module(rb_cMolEnumerable, rb_mEnumerable);
10001 rb_define_method(rb_cMolEnumerable, "[]", s_MolEnumerable_Aref, 1);
10002 rb_define_method(rb_cMolEnumerable, "length", s_MolEnumerable_Length, 0);
10003 rb_define_alias(rb_cMolEnumerable, "size", "length");
10004 rb_define_method(rb_cMolEnumerable, "each", s_MolEnumerable_Each, 0);
10006 /* class AtomRef */
10007 rb_cAtomRef = rb_define_class_under(rb_mMolby, "AtomRef", rb_cObject);
10008 for (i = 0; s_AtomAttrDefTable[i].name != NULL; i++) {
10010 snprintf(buf, sizeof buf - 1, "%s", s_AtomAttrDefTable[i].name);
10011 rb_define_method(rb_cAtomRef, buf, s_AtomAttrDefTable[i].getter, 0);
10012 s_AtomAttrDefTable[i].id = rb_intern(buf);
10013 *(s_AtomAttrDefTable[i].symref) = ID2SYM(s_AtomAttrDefTable[i].id);
10015 rb_define_method(rb_cAtomRef, buf, s_AtomAttrDefTable[i].setter, 1);
10017 rb_define_method(rb_cAtomRef, "[]=", s_AtomRef_SetAttr, 2);
10018 rb_define_alias(rb_cAtomRef, "set_attr", "[]=");
10019 rb_define_method(rb_cAtomRef, "[]", s_AtomRef_GetAttr, 1);
10020 rb_define_alias(rb_cAtomRef, "get_attr", "[]");
10021 s_SetAtomAttrString = rb_str_new2("set_atom_attr");
10022 rb_global_variable(&s_SetAtomAttrString);
10023 rb_define_method(rb_cAtomRef, "molecule", s_AtomRef_GetMolecule, 0);
10025 /* class Parameter */
10026 rb_cParameter = rb_define_class_under(rb_mMolby, "Parameter", rb_cObject);
10027 rb_define_method(rb_cParameter, "bond", s_Parameter_Bond, 1);
10028 rb_define_method(rb_cParameter, "angle", s_Parameter_Angle, 1);
10029 rb_define_method(rb_cParameter, "dihedral", s_Parameter_Dihedral, 1);
10030 rb_define_method(rb_cParameter, "improper", s_Parameter_Improper, 1);
10031 rb_define_method(rb_cParameter, "vdw", s_Parameter_Vdw, 1);
10032 rb_define_method(rb_cParameter, "vdw_pair", s_Parameter_VdwPair, 1);
10033 rb_define_method(rb_cParameter, "vdw_cutoff", s_Parameter_VdwCutoff, 1);
10034 rb_define_method(rb_cParameter, "element", s_Parameter_Element, 1);
10035 rb_define_method(rb_cParameter, "nbonds", s_Parameter_Nbonds, 0);
10036 rb_define_method(rb_cParameter, "nangles", s_Parameter_Nangles, 0);
10037 rb_define_method(rb_cParameter, "ndihedrals", s_Parameter_Ndihedrals, 0);
10038 rb_define_method(rb_cParameter, "nimpropers", s_Parameter_Nimpropers, 0);
10039 rb_define_method(rb_cParameter, "nvdws", s_Parameter_Nvdws, 0);
10040 rb_define_method(rb_cParameter, "nvdw_pairs", s_Parameter_NvdwPairs, 0);
10041 rb_define_method(rb_cParameter, "nvdw_cutoffs", s_Parameter_NvdwCutoffs, 0);
10042 rb_define_method(rb_cParameter, "nelements", s_Parameter_Nelements, 0);
10043 rb_define_method(rb_cParameter, "bonds", s_Parameter_Bonds, 0);
10044 rb_define_method(rb_cParameter, "angles", s_Parameter_Angles, 0);
10045 rb_define_method(rb_cParameter, "dihedrals", s_Parameter_Dihedrals, 0);
10046 rb_define_method(rb_cParameter, "impropers", s_Parameter_Impropers, 0);
10047 rb_define_method(rb_cParameter, "vdws", s_Parameter_Vdws, 0);
10048 rb_define_method(rb_cParameter, "vdw_pairs", s_Parameter_VdwPairs, 0);
10049 rb_define_method(rb_cParameter, "vdw_cutoffs", s_Parameter_VdwCutoffs, 0);
10050 rb_define_method(rb_cParameter, "elements", s_Parameter_Elements, 0);
10051 rb_define_method(rb_cParameter, "lookup", s_Parameter_LookUp, -1);
10052 rb_define_singleton_method(rb_cParameter, "builtin", s_Parameter_Builtin, 0);
10053 rb_define_singleton_method(rb_cParameter, "bond", s_Parameter_Bond, 1);
10054 rb_define_singleton_method(rb_cParameter, "angle", s_Parameter_Angle, 1);
10055 rb_define_singleton_method(rb_cParameter, "dihedral", s_Parameter_Dihedral, 1);
10056 rb_define_singleton_method(rb_cParameter, "improper", s_Parameter_Improper, 1);
10057 rb_define_singleton_method(rb_cParameter, "vdw", s_Parameter_Vdw, 1);
10058 rb_define_singleton_method(rb_cParameter, "vdw_pair", s_Parameter_VdwPair, 1);
10059 rb_define_singleton_method(rb_cParameter, "vdw_cutoff", s_Parameter_VdwCutoff, 1);
10060 rb_define_singleton_method(rb_cParameter, "element", s_Parameter_Element, 1);
10061 rb_define_singleton_method(rb_cParameter, "nbonds", s_Parameter_Nbonds, 0);
10062 rb_define_singleton_method(rb_cParameter, "nangles", s_Parameter_Nangles, 0);
10063 rb_define_singleton_method(rb_cParameter, "ndihedrals", s_Parameter_Ndihedrals, 0);
10064 rb_define_singleton_method(rb_cParameter, "nimpropers", s_Parameter_Nimpropers, 0);
10065 rb_define_singleton_method(rb_cParameter, "nvdws", s_Parameter_Nvdws, 0);
10066 rb_define_singleton_method(rb_cParameter, "nvdw_pairs", s_Parameter_NvdwPairs, 0);
10067 rb_define_singleton_method(rb_cParameter, "nvdw_cutoffs", s_Parameter_NvdwCutoffs, 0);
10068 rb_define_singleton_method(rb_cParameter, "nelements", s_Parameter_Nelements, 0);
10069 rb_define_singleton_method(rb_cParameter, "bonds", s_Parameter_Bonds, 0);
10070 rb_define_singleton_method(rb_cParameter, "angles", s_Parameter_Angles, 0);
10071 rb_define_singleton_method(rb_cParameter, "dihedrals", s_Parameter_Dihedrals, 0);
10072 rb_define_singleton_method(rb_cParameter, "impropers", s_Parameter_Impropers, 0);
10073 rb_define_singleton_method(rb_cParameter, "vdws", s_Parameter_Vdws, 0);
10074 rb_define_singleton_method(rb_cParameter, "vdw_pairs", s_Parameter_VdwPairs, 0);
10075 rb_define_singleton_method(rb_cParameter, "vdw_cutoffs", s_Parameter_VdwCutoffs, 0);
10076 rb_define_singleton_method(rb_cParameter, "elements", s_Parameter_Elements, 0);
10077 rb_define_singleton_method(rb_cParameter, "lookup", s_Parameter_LookUp, -1);
10078 rb_define_const(rb_cParameter, "Builtin", Data_Wrap_Struct(rb_cParameter, 0, NULL, NULL));
10080 /* class ParEnumerable */
10081 rb_cParEnumerable = rb_define_class_under(rb_mMolby, "ParEnumerable", rb_cObject);
10082 rb_include_module(rb_cParEnumerable, rb_mEnumerable);
10083 rb_define_method(rb_cParEnumerable, "par_type", s_ParEnumerable_ParType, 0);
10084 rb_define_method(rb_cParEnumerable, "[]", s_ParEnumerable_Aref, 1);
10085 rb_define_method(rb_cParEnumerable, "length", s_ParEnumerable_Length, 0);
10086 rb_define_method(rb_cParEnumerable, "each", s_ParEnumerable_Each, 0);
10087 rb_define_method(rb_cParEnumerable, "reverse_each", s_ParEnumerable_ReverseEach, 0);
10088 rb_define_method(rb_cParEnumerable, "insert", s_ParEnumerable_Insert, -1);
10089 rb_define_method(rb_cParEnumerable, "delete", s_ParEnumerable_Delete, 1);
10090 rb_define_method(rb_cParEnumerable, "lookup", s_ParEnumerable_LookUp, -1);
10092 /* class ParameterRef */
10093 rb_cParameterRef = rb_define_class_under(rb_mMolby, "ParameterRef", rb_cObject);
10094 for (i = 0; s_ParameterAttrDefTable[i].name != NULL; i++) {
10096 snprintf(buf, sizeof buf - 1, "%s", s_ParameterAttrDefTable[i].name);
10097 rb_define_method(rb_cParameterRef, buf, s_ParameterAttrDefTable[i].getter, 0);
10098 s_ParameterAttrDefTable[i].id = rb_intern(buf);
10099 if (s_ParameterAttrDefTable[i].symref != NULL)
10100 *(s_ParameterAttrDefTable[i].symref) = ID2SYM(s_ParameterAttrDefTable[i].id);
10101 if (s_ParameterAttrDefTable[i].setter != NULL) {
10103 rb_define_method(rb_cParameterRef, buf, s_ParameterAttrDefTable[i].setter, 1);
10106 rb_define_method(rb_cParameterRef, "[]=", s_ParameterRef_SetAttr, 2);
10107 rb_define_alias(rb_cParameterRef, "set_attr", "[]=");
10108 rb_define_method(rb_cParameterRef, "[]", s_ParameterRef_GetAttr, 1);
10109 rb_define_alias(rb_cParameterRef, "get_attr", "[]");
10110 rb_define_method(rb_cParameterRef, "to_hash", s_ParameterRef_ToHash, 0);
10111 rb_define_method(rb_cParameterRef, "to_s", s_ParameterRef_ToString, 0);
10112 rb_define_method(rb_cParameterRef, "keys", s_ParameterRef_Keys, 0);
10114 /* class MolbyError */
10115 rb_eMolbyError = rb_define_class_under(rb_mMolby, "MolbyError", rb_eStandardError);
10117 /* module Kernel */
10118 rb_define_method(rb_mKernel, "check_interrupt", s_Kernel_CheckInterrupt, 0);
10119 rb_define_method(rb_mKernel, "get_interrupt_flag", s_GetInterruptFlag, 0);
10120 rb_define_method(rb_mKernel, "set_interrupt_flag", s_SetInterruptFlag, 1);
10121 rb_define_method(rb_mKernel, "show_progress_panel", s_ShowProgressPanel, -1);
10122 rb_define_method(rb_mKernel, "hide_progress_panel", s_HideProgressPanel, 0);
10123 rb_define_method(rb_mKernel, "set_progress_value", s_SetProgressValue, 1);
10124 rb_define_method(rb_mKernel, "set_progress_message", s_SetProgressMessage, 1);
10125 rb_define_method(rb_mKernel, "ask", s_Kernel_Ask, -1);
10126 rb_define_method(rb_mKernel, "register_menu", s_Kernel_RegisterMenu, 2);
10127 rb_define_method(rb_mKernel, "lookup_menu", s_Kernel_LookupMenu, 1);
10128 rb_define_method(rb_mKernel, "get_global_settings", s_Kernel_GetGlobalSettings, 1);
10129 rb_define_method(rb_mKernel, "set_global_settings", s_Kernel_SetGlobalSettings, 2);
10130 rb_define_method(rb_mKernel, "execute_script", s_Kernel_ExecuteScript, 1);
10131 rb_define_method(rb_mKernel, "document_home", s_Kernel_DocumentHome, 0);
10132 rb_define_method(rb_mKernel, "call_subprocess", s_Kernel_CallSubProcess, 2);
10133 rb_define_method(rb_mKernel, "message_box", s_Kernel_MessageBox, -1);
10134 rb_define_method(rb_mKernel, "error_message_box", s_Kernel_ErrorMessageBox, 1);
10136 s_ID_equal = rb_intern("==");
10139 #pragma mark ====== External functions ======
10141 static VALUE s_ruby_top_self = Qfalse;
10144 s_evalRubyScriptOnMoleculeSub(VALUE val)
10146 void **ptr = (void **)val;
10147 Molecule *mol = (Molecule *)ptr[1];
10148 VALUE sval = rb_str_new2((char *)ptr[0]);
10150 if (s_ruby_top_self == Qfalse) {
10151 s_ruby_top_self = rb_eval_string("eval(\"self\",TOPLEVEL_BINDING)");
10153 if (ptr[2] == NULL) {
10156 fnval = Ruby_NewFileStringValue((char *)ptr[2]);
10160 return rb_funcall(s_ruby_top_self, rb_intern("eval"), 1, sval);
10162 return rb_funcall(s_ruby_top_self, rb_intern("eval"), 4, sval, Qnil, fnval, INT2FIX(1));
10164 VALUE mval = ValueFromMolecule(mol);
10166 return rb_funcall(mval, rb_intern("instance_eval"), 1, sval);
10167 else return rb_funcall(mval, rb_intern("instance_eval"), 3, sval, fnval, INT2FIX(1));
10172 Molby_evalRubyScriptOnMolecule(const char *script, Molecule *mol, const char *fname, int *status)
10176 VALUE save_interrupt_flag;
10177 char *save_ruby_sourcefile;
10178 int save_ruby_sourceline;
10179 if (gMolbyIsCheckingInterrupt) {
10180 MolActionAlertRubyIsRunning();
10182 return (RubyValue)Qnil;
10185 args[0] = (void *)script;
10186 args[1] = (void *)mol;
10187 args[2] = (void *)fname;
10188 save_interrupt_flag = s_SetInterruptFlag(Qnil, Qtrue);
10189 save_ruby_sourcefile = ruby_sourcefile;
10190 save_ruby_sourceline = ruby_sourceline;
10191 retval = (RubyValue)rb_protect(s_evalRubyScriptOnMoleculeSub, (VALUE)args, status);
10192 if (*status != 0) {
10193 /* Is this 'exit' exception? */
10194 VALUE last_exception = rb_gv_get("$!");
10195 if (rb_obj_is_kind_of(last_exception, rb_eSystemExit)) {
10196 /* Capture exit and return the status value */
10197 retval = (RubyValue)rb_funcall(last_exception, rb_intern("status"), 0);
10201 s_SetInterruptFlag(Qnil, save_interrupt_flag);
10202 ruby_sourcefile = save_ruby_sourcefile;
10203 ruby_sourceline = save_ruby_sourceline;
10209 Molby_showRubyValue(RubyValue value, char **outValueString)
10211 VALUE val = (VALUE)value;
10212 if (gMolbyIsCheckingInterrupt) {
10213 MolActionAlertRubyIsRunning();
10220 val = rb_protect(rb_inspect, val, &status);
10222 str = StringValuePtr(val);
10223 MyAppCallback_showScriptMessage("%s", str);
10224 if (outValueString != NULL)
10225 *outValueString = strdup(str);
10230 Molby_showError(int status)
10232 static const int tag_raise = 6;
10233 char *msg = NULL, *msg2;
10234 VALUE val, backtrace;
10235 int interrupted = 0;
10236 if (status == tag_raise) {
10237 VALUE eclass = CLASS_OF(ruby_errinfo);
10238 if (eclass == rb_eInterrupt) {
10244 backtrace = rb_eval_string_protect("$backtrace = $!.backtrace.join(\"\\n\")", &status);
10246 val = rb_eval_string_protect("$!.to_s", &status);
10248 msg = RSTRING_PTR(val);
10249 else msg = "(message not available)";
10251 asprintf(&msg2, "%s\n%s", msg, RSTRING_PTR(backtrace));
10252 MyAppCallback_messageBox(msg2, (interrupted == 0 ? "Molby script error" : "Molby script interrupted"), 0, 3);
10258 Molby_getDescription(void)
10260 extern const char *gVersionString, *gCopyrightString;
10261 extern int gRevisionNumber;
10262 extern char *gLastBuildString;
10264 char *revisionString;
10265 if (gRevisionNumber > 0) {
10266 asprintf(&revisionString, ", revision %d", gRevisionNumber);
10267 } else revisionString = "";
10269 "Molby %s%s\n%s\nLast compile: %s\n"
10270 #if !defined(__CMDMAC__)
10277 gVersionString, revisionString, gCopyrightString, gLastBuildString,
10278 #if !defined(__CMDMAC__)
10279 MyAppCallback_getGUIDescriptionString(),
10281 gRubyVersion, gRubyCopyright);
10282 if (revisionString[0] != 0)
10283 free(revisionString);
10288 Molby_startup(const char *script, const char *dir)
10293 char *respath, *p, *wbuf;
10295 /* Get version/copyright string from Ruby interpreter */
10297 gRubyVersion = strdup(ruby_version);
10298 asprintf(&gRubyCopyright, "%sCopyright (C) %d-%d %s",
10299 #if defined(__CMDMAC__)
10302 " ", /* Indent for displaying in About dialog */
10304 RUBY_BIRTH_YEAR, RUBY_RELEASE_YEAR, RUBY_AUTHOR);
10307 /* Read build and revision information for Molby */
10310 extern int gRevisionNumber;
10311 extern char *gLastBuildString;
10312 FILE *fp = fopen("../buildInfo.txt", "r");
10313 gLastBuildString = "";
10315 if (fgets(buf, sizeof(buf), fp) != NULL) {
10316 char *p1 = strchr(buf, '\"');
10317 char *p2 = strrchr(buf, '\"');
10318 if (p1 != NULL && p2 != NULL && p2 - p1 > 1) {
10319 memmove(buf, p1 + 1, p2 - p1 - 1);
10320 buf[p2 - p1 - 1] = 0;
10321 asprintf(&gLastBuildString, "Last compile: %s\n", buf);
10326 fp = fopen("../revisionInfo.txt", "r");
10327 gRevisionNumber = 0;
10329 if (fgets(buf, sizeof(buf), fp) != NULL) {
10330 gRevisionNumber = strtol(buf, NULL, 0);
10336 #if defined(__CMDMAC__)
10337 wbuf = Molby_getDescription();
10338 printf("%s\n", wbuf);
10342 /* Read atom display parameters */
10343 if (ElementParameterInitialize("element.par", &wbuf) != 0) {
10344 #if defined(__CMDMAC__)
10345 fprintf(stderr, "%s\n", wbuf);
10347 MyAppCallback_setConsoleColor(1);
10348 MyAppCallback_showScriptMessage("%s", wbuf);
10349 MyAppCallback_setConsoleColor(0);
10354 /* Read default parameters */
10355 ParameterReadFromFile(gBuiltinParameters, "default.par", &wbuf, NULL);
10356 if (wbuf != NULL) {
10357 #if defined(__CMDMAC__)
10358 fprintf(stderr, "%s\n", wbuf);
10360 MyAppCallback_setConsoleColor(1);
10361 MyAppCallback_showScriptMessage("%s", wbuf);
10362 MyAppCallback_setConsoleColor(0);
10367 /* Initialize Ruby interpreter */
10370 /* Initialize loadpath; the specified directory, "lib" subdirectory, and "." */
10372 asprintf(&libpath, "%s%clib", dir, PATH_SEPARATOR);
10373 ruby_incpush(libpath);
10377 ruby_script("Molby");
10379 /* Find the resource path (the parent directory of the given directory) */
10380 respath = strdup(dir);
10381 p = strrchr(respath, '/');
10382 if (p == NULL && PATH_SEPARATOR != '/')
10383 p = strrchr(respath, PATH_SEPARATOR);
10386 val = Ruby_NewFileStringValue(respath);
10387 rb_define_global_const("MolbyResourcePath", val);
10390 /* Define Molby classes */
10392 RubyDialogInitClass();
10394 rb_define_const(rb_mMolby, "ResourcePath", val);
10395 val = Ruby_NewFileStringValue(dir);
10396 rb_define_const(rb_mMolby, "ScriptPath", val);
10397 asprintf(&p, "%s%c%s", dir, PATH_SEPARATOR, "mbsf");
10398 val = Ruby_NewFileStringValue(p);
10399 rb_define_const(rb_mMolby, "MbsfPath", val);
10402 #if defined(__CMDMAC__)
10403 rb_define_const(rb_mMolby, "HasGUI", Qfalse);
10405 rb_define_const(rb_mMolby, "HasGUI", Qtrue);
10410 /* Create objects for stdout and stderr */
10411 val = rb_funcall(rb_cObject, rb_intern("new"), 0);
10412 rb_define_singleton_method(val, "write", s_StandardOutput, 1);
10413 rb_gv_set("$stdout", val);
10414 val = rb_funcall(rb_cObject, rb_intern("new"), 0);
10415 rb_define_singleton_method(val, "write", s_StandardErrorOutput, 1);
10416 rb_gv_set("$stderr", val);
10418 /* Create objects for stdin */
10419 val = rb_funcall(rb_cObject, rb_intern("new"), 0);
10420 rb_define_singleton_method(val, "gets", s_StandardInputGets, -1);
10421 rb_define_singleton_method(val, "readline", s_StandardInputGets, -1);
10422 rb_define_singleton_method(val, "method_missing", s_StandardInputMethodMissing, -1);
10423 rb_gv_set("$stdin", val);
10427 /* Global variable to hold backtrace */
10428 rb_define_variable("$backtrace", &gMolbyBacktrace);
10431 /* Register interrupt check code */
10432 rb_add_event_hook(s_Event_Callback, RUBY_EVENT_ALL);
10436 /* Start interval timer (for periodic polling of interrupt); firing every 50 msec */
10437 s_SetIntervalTimer(0, 50);
10440 /* Read the startup script */
10441 if (script != NULL && script[0] != 0) {
10442 MyAppCallback_showScriptMessage("Evaluating %s...\n", script);
10444 rb_load_protect(rb_str_new2(script), 0, &status);
10447 Molby_showError(status);
10449 MyAppCallback_showScriptMessage("Done.\n");
10454 Molby_buildARGV(int argc, const char **argv)
10457 rb_ary_clear(rb_argv);
10458 for (i = 0; i < argc; i++) {
10459 VALUE arg = rb_tainted_str_new2(argv[i]);
10461 rb_ary_push(rb_argv, arg);