Update Colvars library to version 2024-06-04

This commit is contained in:
Giacomo Fiorin
2024-08-06 01:07:43 +02:00
parent 278accd9ea
commit 133dee9ac1
74 changed files with 7343 additions and 4676 deletions

View File

@ -25,6 +25,7 @@ COLVARS_INCFLAGS = -DCOLVARS_LAMMPS $(COLVARS_DEBUG_INCFLAGS) $(COLVARS_PYTHON_I
COLVARS_SRCS = \ COLVARS_SRCS = \
colvaratoms.cpp \ colvaratoms.cpp \
colvarbias_abf.cpp \ colvarbias_abf.cpp \
colvarbias_abmd.cpp \
colvarbias_alb.cpp \ colvarbias_alb.cpp \
colvarbias.cpp \ colvarbias.cpp \
colvarbias_histogram.cpp \ colvarbias_histogram.cpp \
@ -59,6 +60,7 @@ COLVARS_SRCS = \
colvarscript_commands.cpp \ colvarscript_commands.cpp \
colvarscript_commands_bias.cpp \ colvarscript_commands_bias.cpp \
colvarscript_commands_colvar.cpp \ colvarscript_commands_colvar.cpp \
colvars_memstream.cpp \
colvartypes.cpp \ colvartypes.cpp \
colvarvalue.cpp \ colvarvalue.cpp \
colvar_neuralnetworkcompute.cpp colvar_neuralnetworkcompute.cpp

View File

@ -1,201 +1,230 @@
$(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvardeps.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvarmodule.h colvars_version.h colvarparse.h colvarvalue.h \
colvartypes.h ../../src/math_eigen_impl.h colvarparams.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvarparse.h colvarparams.h colvaratoms.h \ colvarproxy_volmaps.h colvaratoms.h colvar_rotation_derivative.h
colvardeps.h
$(COLVARS_OBJ_DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h \
colvars_version.h colvar.h colvarvalue.h colvartypes.h colvarparse.h \ colvars_version.h colvar.h colvarvalue.h colvartypes.h \
colvarparams.h colvardeps.h colvarbias_abf.h colvarproxy.h \ ../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvarbias_abf.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvarbias.h colvargrid.h colvar_UIestimator.h colvarproxy_tcl.h colvarproxy_volmaps.h colvarbias.h colvargrid.h \
colvar_UIestimator.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_abmd.o: colvarbias_abmd.cpp \
colvarbias_abmd.h colvarbias_restraint.h colvarbias.h colvar.h \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h
$(COLVARS_OBJ_DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h \
colvars_version.h colvarbias.h colvar.h colvarvalue.h colvartypes.h \ colvars_version.h colvarproxy.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h colvarbias_alb.h ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvarbias.h colvar.h \
colvarvalue.h colvarparse.h colvarparams.h colvardeps.h colvarbias_alb.h
$(COLVARS_OBJ_DIR)colvarbias.o: colvarbias.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarbias.o: colvarbias.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvars_version.h colvarproxy.h colvartypes.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvarbias.h colvar.h colvarparse.h colvarparams.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvarvalue.h colvarbias.h \
colvardeps.h colvargrid.h colvar.h colvarparse.h colvarparams.h colvardeps.h colvargrid.h \
colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \ $(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \
colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \ colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvar.h colvarparse.h colvarparams.h colvardeps.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvarvalue.h \
colvarbias_histogram.h colvarbias.h colvargrid.h colvarparse.h colvarparams.h colvardeps.h colvarbias_histogram.h \
colvarbias.h colvargrid.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_histogram_reweight_amd.o: \ $(COLVARS_OBJ_DIR)colvarbias_histogram_reweight_amd.o: \
colvarbias_histogram_reweight_amd.cpp \ colvarbias_histogram_reweight_amd.cpp \
colvarbias_histogram_reweight_amd.h colvarbias_histogram.h colvarbias.h \ colvarbias_histogram_reweight_amd.h colvarbias_histogram.h colvarbias.h \
colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h colvargrid.h colvarproxy.h \ ../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvargrid.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvarproxy_tcl.h colvarproxy_volmaps.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvars_version.h colvarproxy.h colvartypes.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvar.h colvarparse.h colvarparams.h colvardeps.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvarvalue.h \
colvarbias_meta.h colvarbias.h colvargrid.h colvarparse.h colvarparams.h colvardeps.h colvarbias_meta.h colvarbias.h \
colvargrid.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \ $(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \
colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \ colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvarbias_restraint.h colvarbias.h colvar.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvarvalue.h \
colvarparse.h colvarparams.h colvardeps.h colvarbias_restraint.h colvarbias.h colvar.h colvarparse.h \
colvarparams.h colvardeps.h
$(COLVARS_OBJ_DIR)colvarcomp_alchlambda.o: colvarcomp_alchlambda.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_alchlambda.o: colvarcomp_alchlambda.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvar.h colvardeps.h colvarcomp.h \ ../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvaratoms.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \ colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar_arithmeticpath.h \ colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_geometricpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_angles.o: colvarcomp_angles.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_angles.o: colvarcomp_angles.cpp \
colvarmodule.h colvars_version.h colvar.h colvarvalue.h colvartypes.h \ colvarmodule.h colvars_version.h colvar.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h colvarcomp.h colvaratoms.h \ ../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
$(COLVARS_OBJ_DIR)colvarcomp_apath.o: colvarcomp_apath.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \
colvarparams.h colvar.h colvardeps.h colvarcomp.h colvaratoms.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp \
colvarmodule.h colvars_version.h colvarparse.h colvarvalue.h \
colvartypes.h colvarparams.h colvaratoms.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvardeps.h colvar.h colvarcomp.h \
colvar_arithmeticpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvar.h colvarparse.h \
colvarparams.h colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_distances.o: colvarcomp_distances.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvar.h colvardeps.h colvarcomp.h \
colvaratoms.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar_arithmeticpath.h \
colvar_geometricpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_gpath.o: colvarcomp_gpath.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarcomp_apath.o: colvarcomp_apath.cpp colvarvalue.h \
colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \ colvarmodule.h colvars_version.h colvartypes.h \
colvarparams.h colvar.h colvardeps.h colvarcomp.h colvaratoms.h \ ../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_neuralnetwork.o: \
colvarcomp_neuralnetwork.cpp colvarmodule.h colvars_version.h \
colvarvalue.h colvartypes.h colvarparse.h colvarparams.h colvar.h \
colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \ colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \ colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_arithmeticpath.h colvar_geometricpath.h \ colvar_geometricpath.h colvar_arithmeticpath.h
$(COLVARS_OBJ_DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp \
colvarmodule.h colvars_version.h colvaratoms.h colvarproxy.h \
colvartypes.h ../../src/math_eigen_impl.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvarparse.h colvarvalue.h colvarparams.h colvardeps.h colvar.h \
colvarcomp.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_distances.o: colvarcomp_distances.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_geometricpath.h colvar_rotation_derivative.h
$(COLVARS_OBJ_DIR)colvarcomp_gpath.o: colvarcomp_gpath.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_neuralnetwork.o: \
colvarcomp_neuralnetwork.cpp colvarmodule.h colvars_version.h \
colvarvalue.h colvartypes.h ../../src/math_eigen_impl.h colvar.h \
colvarparse.h colvarparams.h colvardeps.h colvarcomp.h colvaratoms.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_geometricpath.h \
colvar_neuralnetworkcompute.h colvar_neuralnetworkcompute.h
$(COLVARS_OBJ_DIR)colvarcomp_combination.o: colvarcomp_combination.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_combination.o: colvarcomp_combination.cpp \
colvarcomp.h colvarmodule.h colvars_version.h colvar.h colvarvalue.h \ colvarcomp.h colvarmodule.h colvars_version.h colvaratoms.h \
colvartypes.h colvarparse.h colvarparams.h colvardeps.h colvaratoms.h \ colvarproxy.h colvartypes.h ../../src/math_eigen_impl.h colvarproxy_io.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h colvarparse.h colvarvalue.h colvarparams.h colvardeps.h colvar.h \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvar.h colvardeps.h colvarcomp.h \ ../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvaratoms.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \ colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar_arithmeticpath.h \ colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_geometricpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvar.h colvardeps.h colvarcomp.h \ ../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvaratoms.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar_arithmeticpath.h \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_volmaps.o: colvarcomp_volmaps.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvar.h colvardeps.h colvarcomp.h \
colvaratoms.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar_arithmeticpath.h \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvar.o: colvar.cpp colvarmodule.h colvars_version.h \
colvarvalue.h colvartypes.h colvarparse.h colvarparams.h colvar.h \
colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \ colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \ colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_arithmeticpath.h colvar_geometricpath.h colvarscript.h \ colvar_geometricpath.h colvar_rotation_derivative.h
colvarbias.h colvarscript_commands.h colvarscript_commands_colvar.h \ $(COLVARS_OBJ_DIR)colvarcomp_volmaps.o: colvarcomp_volmaps.cpp \
colvarscript_commands_bias.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvar.h colvarparse.h colvarparams.h \
colvardeps.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvar.o: colvar.cpp colvarmodule.h colvars_version.h \
colvarvalue.h colvartypes.h ../../src/math_eigen_impl.h colvarparse.h \
colvarparams.h colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvardeps.h colvar.h colvar_geometricpath.h colvarbias.h \
colvars_memstream.h
$(COLVARS_OBJ_DIR)colvardeps.o: colvardeps.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvardeps.o: colvardeps.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvars_version.h colvarproxy.h colvartypes.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h colvarparse.h \
colvarvalue.h colvarparams.h
$(COLVARS_OBJ_DIR)colvargrid.o: colvargrid.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvargrid.o: colvargrid.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \ colvars_version.h colvarvalue.h colvartypes.h \
colvarparams.h colvar.h colvardeps.h colvarcomp.h colvaratoms.h \ ../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvar.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvardeps.h colvargrid.h colvargrid_def.h colvarproxy.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h \ colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvargrid.h colvargrid_def.h colvarproxy_volmaps.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \
colvars_version.h colvarparse.h colvarvalue.h colvartypes.h \ colvars_version.h colvarparse.h colvarvalue.h colvartypes.h \
colvarparams.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \ ../../src/math_eigen_impl.h colvarparams.h colvarproxy.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvardeps.h \
colvarbias.h colvarbias_abf.h colvargrid.h colvar_UIestimator.h \
colvarbias_alb.h colvarbias_histogram.h \
colvarbias_histogram_reweight_amd.h colvarbias_meta.h \
colvarbias_restraint.h colvarscript.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h \
colvaratoms.h colvarcomp.h colvar_arithmeticpath.h \
colvar_geometricpath.h colvarmodule_refs.h
$(COLVARS_OBJ_DIR)colvarparams.o: colvarparams.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvarparams.h
$(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \
colvarparams.h
$(COLVARS_OBJ_DIR)colvarproxy.o: colvarproxy.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvarscript.h colvarbias.h colvar.h colvarparse.h \ colvarproxy_volmaps.h colvar.h colvardeps.h colvarbias.h \
colvarparams.h colvardeps.h colvarscript_commands.h \ colvarbias_abf.h colvargrid.h colvar_UIestimator.h colvarbias_abmd.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h \ colvarbias_restraint.h colvarbias_alb.h colvarbias_histogram.h \
colvaratoms.h colvarmodule_utils.h colvarbias_histogram_reweight_amd.h colvarbias_meta.h colvarscript.h \
colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h colvaratoms.h colvarcomp.h \
colvar_geometricpath.h colvars_memstream.h colvarmodule_refs.h
$(COLVARS_OBJ_DIR)colvarparams.o: colvarparams.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvarparams.h
$(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvarparse.h colvarparams.h \
colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarproxy.o: colvarproxy.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h \
../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvarvalue.h \
colvarparse.h colvarparams.h colvardeps.h colvarbias.h colvarscript.h \
colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h colvarmodule_utils.h
$(COLVARS_OBJ_DIR)colvarproxy_io.o: colvarproxy_io.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarproxy_io.o: colvarproxy_io.cpp colvarmodule.h \
colvars_version.h colvarproxy_io.h colvars_version.h colvarproxy_io.h
$(COLVARS_OBJ_DIR)colvarproxy_replicas.o: colvarproxy_replicas.cpp \ $(COLVARS_OBJ_DIR)colvarproxy_replicas.o: colvarproxy_replicas.cpp \
colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \ colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvarproxy_tcl.h colvarproxy_volmaps.h
$(COLVARS_OBJ_DIR)colvarproxy_system.o: colvarproxy_system.cpp \ $(COLVARS_OBJ_DIR)colvarproxy_system.o: colvarproxy_system.cpp \
colvarmodule.h colvars_version.h colvartypes.h colvarproxy_system.h colvarmodule.h colvars_version.h colvartypes.h \
../../src/math_eigen_impl.h colvarproxy_system.h
$(COLVARS_OBJ_DIR)colvarproxy_tcl.o: colvarproxy_tcl.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarproxy_tcl.o: colvarproxy_tcl.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvars_version.h colvarproxy.h colvartypes.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvaratoms.h colvarparse.h colvarparams.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvaratoms.h colvarparse.h \
colvardeps.h colvarvalue.h colvarparams.h colvardeps.h
$(COLVARS_OBJ_DIR)colvarproxy_volmaps.o: colvarproxy_volmaps.cpp \ $(COLVARS_OBJ_DIR)colvarproxy_volmaps.o: colvarproxy_volmaps.cpp \
colvarmodule.h colvars_version.h colvarproxy_volmaps.h \ colvarmodule.h colvars_version.h colvarproxy_volmaps.h \
colvarmodule_utils.h colvarmodule_utils.h
$(COLVARS_OBJ_DIR)colvarscript.o: colvarscript.cpp colvarproxy.h \ $(COLVARS_OBJ_DIR)colvarscript.o: colvarscript.cpp colvarproxy.h \
colvarmodule.h colvars_version.h colvartypes.h colvarvalue.h \ colvarmodule.h colvars_version.h colvartypes.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h colvarparse.h \
colvarscript.h colvarbias.h colvar.h colvarscript_commands.h \ colvarvalue.h colvarparams.h colvarscript.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h colvarscript_commands_colvar.h colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvarscript_commands.o: colvarscript_commands.cpp \ $(COLVARS_OBJ_DIR)colvarscript_commands.o: colvarscript_commands.cpp \
colvarproxy.h colvarmodule.h colvars_version.h colvartypes.h \ colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \ ../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h \ colvarbias.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarscript.h colvarbias.h colvar.h colvarscript_commands.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvarscript.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvarscript_commands_bias.o: \ $(COLVARS_OBJ_DIR)colvarscript_commands_bias.o: \
colvarscript_commands_bias.cpp colvarproxy.h colvarmodule.h \ colvarscript_commands_bias.cpp colvarproxy.h colvarmodule.h \
colvars_version.h colvartypes.h colvarvalue.h colvarproxy_io.h \ colvars_version.h colvartypes.h ../../src/math_eigen_impl.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \ colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvardeps.h colvarparse.h colvarparams.h colvarscript.h colvarbias.h \ colvarproxy_volmaps.h colvarbias.h colvar.h colvarvalue.h colvarparse.h \
colvar.h colvarscript_commands.h colvarscript_commands_colvar.h \ colvarparams.h colvardeps.h colvarscript.h colvarscript_commands.h \
colvarscript_commands_bias.h colvarscript_commands_colvar.h colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvarscript_commands_colvar.o: \ $(COLVARS_OBJ_DIR)colvarscript_commands_colvar.o: \
colvarscript_commands_colvar.cpp colvarproxy.h colvarmodule.h \ colvarscript_commands_colvar.cpp colvar.h colvarmodule.h \
colvars_version.h colvartypes.h colvarvalue.h colvarproxy_io.h \ colvars_version.h colvarvalue.h colvartypes.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \ ../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvardeps.h colvarparse.h colvarparams.h colvarscript.h colvarbias.h \ colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvar.h colvarscript_commands.h colvarscript_commands_colvar.h \ colvarproxy_volmaps.h colvarscript.h colvarscript_commands.h \
colvarscript_commands_bias.h colvarscript_commands_colvar.h colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvars_memstream.o: colvars_memstream.cpp \
colvarmodule.h colvars_version.h colvartypes.h \
../../src/math_eigen_impl.h colvarvalue.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \
colvars_version.h colvartypes.h colvarparse.h colvarvalue.h \ colvars_version.h colvartypes.h ../../src/math_eigen_impl.h \
colvarparams.h ../../src/math_eigen_impl.h colvaratoms.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvarparse.h colvarvalue.h \
colvarparams.h colvardeps.h colvar_rotation_derivative.h
$(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvar_neuralnetworkcompute.o: \ $(COLVARS_OBJ_DIR)colvar_neuralnetworkcompute.o: \
colvar_neuralnetworkcompute.cpp colvar_neuralnetworkcompute.h \ colvar_neuralnetworkcompute.cpp colvar_neuralnetworkcompute.h \
colvarparse.h colvarmodule.h colvars_version.h colvarvalue.h \ colvarparse.h colvarmodule.h colvars_version.h colvarvalue.h \
colvartypes.h colvarparams.h colvarproxy.h colvarproxy_io.h \ colvartypes.h ../../src/math_eigen_impl.h colvarparams.h colvarproxy.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h

View File

@ -16,13 +16,18 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h" #include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
#include "colvarscript.h" #include "colvar.h"
#include "colvarbias.h"
#include "colvars_memstream.h"
std::map<std::string, std::function<colvar::cvc *()>> colvar::global_cvc_map =
std::map<std::string, std::function<colvar::cvc *()>>();
std::map<std::string, std::string> colvar::global_cvc_desc_map =
std::map<std::string, std::string>();
#if (__cplusplus >= 201103L)
std::map<std::string, std::function<colvar::cvc* (const std::string& subcv_conf)>> colvar::global_cvc_map = std::map<std::string, std::function<colvar::cvc* (const std::string& subcv_conf)>>();
#endif
colvar::colvar() colvar::colvar()
{ {
@ -36,6 +41,8 @@ colvar::colvar()
dev_null = 0.0; dev_null = 0.0;
#endif #endif
matching_state = false;
expand_boundaries = false; expand_boundaries = false;
description = "uninitialized colvar"; description = "uninitialized colvar";
@ -131,7 +138,14 @@ int colvar::init(std::string const &conf)
// Sort array of cvcs based on their names // Sort array of cvcs based on their names
// Note: default CVC names are in input order for same type of CVC // Note: default CVC names are in input order for same type of CVC
std::sort(cvcs.begin(), cvcs.end(), colvar::compare_cvc); std::sort(cvcs.begin(), cvcs.end(),
[](std::shared_ptr<colvar::cvc> const &cvc1,
std::shared_ptr<colvar::cvc> const &cvc2) -> bool {
if (cvc1 && cvc2) {
return cvc1->name < cvc2->name;
}
return false;
});
if(cvcs.size() > 1) { if(cvcs.size() > 1) {
cvm::log("Sorted list of components for this scripted colvar:\n"); cvm::log("Sorted list of components for this scripted colvar:\n");
@ -186,9 +200,9 @@ int colvar::init(std::string const &conf)
if ((cvcs[i])->sup_np < 0) { if ((cvcs[i])->sup_np < 0) {
cvm::log("Warning: you chose a negative exponent in the combination; " cvm::log("Warning: you chose a negative exponent in the combination; "
"if you apply forces, the simulation may become unstable " "if you apply forces, the simulation may become unstable "
"when the component \""+ "when the component \""+
(cvcs[i])->function_type+"\" approaches zero.\n"); (cvcs[i])->function_type()+"\" approaches zero.\n");
} }
} }
} }
@ -295,7 +309,7 @@ int colvar::init(std::string const &conf)
error_code |= init_grid_parameters(conf); error_code |= init_grid_parameters(conf);
// Detect if we have a single component that is an alchemical lambda // Detect if we have a single component that is an alchemical lambda
if (is_enabled(f_cv_single_cvc) && cvcs[0]->function_type == "alchLambda") { if (is_enabled(f_cv_single_cvc) && cvcs[0]->function_type() == "alchLambda") {
enable(f_cv_external); enable(f_cv_external);
} }
@ -468,13 +482,6 @@ int colvar::init_custom_function(std::string const &conf)
size_t pos = 0; size_t pos = 0;
if (key_lookup(conf, "customFunction", &expr, &pos)) { if (key_lookup(conf, "customFunction", &expr, &pos)) {
std::string msg("Error: customFunction requires the Lepton library."); std::string msg("Error: customFunction requires the Lepton library.");
#if (__cplusplus < 201103L)
// NOTE: this is not ideal; testing for the Lepton library's version would
// be more accurate, but also less portable
msg +=
std::string(" Note also that recent versions of Lepton require C++11: "
"please see https://colvars.github.io/README-c++11.html.");
#endif
return cvm::error(msg, COLVARS_NOT_IMPLEMENTED); return cvm::error(msg, COLVARS_NOT_IMPLEMENTED);
} }
@ -697,9 +704,14 @@ int colvar::init_extended_Lagrangian(std::string const &conf)
} }
if (ext_gamma != 0.0) { if (ext_gamma != 0.0) {
enable(f_cv_Langevin); enable(f_cv_Langevin);
cvm::main()->cite_feature("BAOA integrator");
ext_gamma *= 1.0e-3; // correct as long as input is required in ps-1 and cvm::dt() is in fs ext_gamma *= 1.0e-3; // correct as long as input is required in ps-1 and cvm::dt() is in fs
// Adjust Langevin sigma for slow time step if time_step_factor != 1 // Adjust Langevin sigma for slow time step if time_step_factor != 1
ext_sigma = cvm::sqrt(2.0 * proxy->boltzmann() * temp * ext_gamma * ext_mass / (cvm::dt() * cvm::real(time_step_factor))); // Eq. (6a) in https://doi.org/10.1021/acs.jctc.2c00585
ext_sigma = cvm::sqrt((1.0 - cvm::exp(-2.0 * ext_gamma * cvm::dt() * cvm::real(time_step_factor)))
* ext_mass * proxy->boltzmann() * temp);
} else {
ext_sigma = 0.0;
} }
get_keyval_feature(this, conf, "reflectingLowerBoundary", f_cv_reflecting_lower_boundary, false); get_keyval_feature(this, conf, "reflectingLowerBoundary", f_cv_reflecting_lower_boundary, false);
@ -744,75 +756,56 @@ int colvar::init_output_flags(std::string const &conf)
return COLVARS_OK; return COLVARS_OK;
} }
#if (__cplusplus >= 201103L)
// C++11 template <typename def_class_name>
template<typename def_class_name> int colvar::init_components_type(std::string const &, void colvar::add_component_type(char const *def_description, char const *def_config_key)
char const * /* def_desc */, {
char const *def_config_key) { if (global_cvc_map.count(def_config_key) == 0) {
// global_cvc_map is only supported in the C++11 case global_cvc_map[def_config_key] = []() {
global_cvc_map[def_config_key] = [](const std::string& cvc_conf){return new def_class_name(cvc_conf);}; return new def_class_name();
// TODO: maybe it is better to do more check to avoid duplication in the map? };
return COLVARS_OK; global_cvc_desc_map[def_config_key] = std::string(def_description);
}
} }
int colvar::init_components_type_from_global_map(const std::string& conf,
const char* def_config_key) { int colvar::init_components_type(const std::string& conf, const char* def_config_key) {
#else
template<typename def_class_name> int colvar::init_components_type(std::string const & conf,
char const * /* def_desc */,
char const *def_config_key) {
#endif
size_t def_count = 0; size_t def_count = 0;
std::string def_conf = ""; std::string def_conf = "";
size_t pos = 0; size_t pos = 0;
int error_code = COLVARS_OK;
while ( this->key_lookup(conf, while ( this->key_lookup(conf,
def_config_key, def_config_key,
&def_conf, &def_conf,
&pos) ) { &pos) ) {
if (!def_conf.size()) continue;
cvm::log("Initializing " cvm::log("Initializing "
"a new \""+std::string(def_config_key)+"\" component"+ "a new \""+std::string(def_config_key)+"\" component"+
(cvm::debug() ? ", with configuration:\n"+def_conf (cvm::debug() ? ", with configuration:\n"+def_conf
: ".\n")); : ".\n"));
cvc *cvcp = global_cvc_map[def_config_key]();
if (!cvcp) {
return cvm::error("Error: in creating object of type \"" + std::string(def_config_key) +
"\".\n",
COLVARS_MEMORY_ERROR);
}
cvcs.push_back(std::shared_ptr<colvar::cvc>(cvcp));
cvm::increase_depth(); cvm::increase_depth();
// only the following line is different from init_components_type int error_code_this = cvcp->init(def_conf);
// in the non-C++11 case if (error_code_this == COLVARS_OK) {
#if (__cplusplus >= 201103L) // Checking for invalid keywords only if the parsing was successful, otherwise any
cvc *cvcp = global_cvc_map.at(def_config_key)(def_conf); // early-returns due to errors would raise false positives
#else error_code_this |= cvcp->check_keywords(def_conf, def_config_key);
cvc *cvcp = new def_class_name(def_conf); }
#endif cvm::decrease_depth();
if (cvcp != NULL) { if (error_code_this != COLVARS_OK) {
cvcs.push_back(cvcp); error_code |=
cvcp->check_keywords(def_conf, def_config_key); cvm::error("Error: in setting up component \"" + std::string(def_config_key) + "\".\n",
cvcp->set_function_type(def_config_key); COLVARS_INPUT_ERROR);
if (cvm::get_error()) {
cvm::error("Error: in setting up component \""+
std::string(def_config_key)+"\".\n", COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
}
cvm::decrease_depth();
} else {
cvm::decrease_depth();
cvm::error("Error: in allocating component \""+
std::string(def_config_key)+"\".\n",
COLVARS_MEMORY_ERROR);
return COLVARS_MEMORY_ERROR;
}
if ( (cvcp->period != 0.0) || (cvcp->wrap_center != 0.0) ) {
if (! cvcp->is_enabled(f_cvc_periodic)) {
cvm::error("Error: invalid use of period and/or "
"wrapAround in a \""+
std::string(def_config_key)+
"\" component.\n"+
"Period: "+cvm::to_str(cvcp->period) +
" wrapAround: "+cvm::to_str(cvcp->wrap_center),
COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
}
} }
// Set default name if it doesn't have one
if ( ! cvcs.back()->name.size()) { if ( ! cvcs.back()->name.size()) {
std::ostringstream s; std::ostringstream s;
s << def_config_key << std::setfill('0') << std::setw(4) << ++def_count; s << def_config_key << std::setfill('0') << std::setw(4) << ++def_count;
@ -822,135 +815,138 @@ template<typename def_class_name> int colvar::init_components_type(std::string c
cvcs.back()->setup(); cvcs.back()->setup();
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Done initializing a \""+ cvm::log("Done initializing a \"" + std::string(def_config_key) + "\" component" +
std::string(def_config_key)+ (cvm::debug() ? ", named \"" + cvcs.back()->name + "\"" : "") + ".\n");
"\" component"+
(cvm::debug() ?
", named \""+cvcs.back()->name+"\""
: "")+".\n");
} }
def_conf = ""; def_conf = "";
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Parsed "+cvm::to_str(cvcs.size())+ cvm::log("Parsed " + cvm::to_str(cvcs.size()) + " components at this time.\n");
" components at this time.\n");
} }
} }
return COLVARS_OK; return error_code;
} }
void colvar::define_component_types()
{
colvarproxy *proxy = cvm::main()->proxy;
add_component_type<distance>("distance", "distance");
add_component_type<distance_vec>("distance vector", "distanceVec");
add_component_type<cartesian>("Cartesian coordinates", "cartesian");
add_component_type<distance_dir>("distance vector direction", "distanceDir");
add_component_type<distance_z>("distance projection on an axis", "distanceZ");
add_component_type<distance_xy>("distance projection on a plane", "distanceXY");
add_component_type<polar_theta>("spherical polar angle theta", "polarTheta");
add_component_type<polar_phi>("spherical azimuthal angle phi", "polarPhi");
add_component_type<distance_inv>("average distance weighted by inverse power", "distanceInv");
add_component_type<distance_pairs>("N1xN2-long vector of pairwise distances", "distancePairs");
add_component_type<dipole_magnitude>("dipole magnitude", "dipoleMagnitude");
add_component_type<coordnum>("coordination number", "coordNum");
add_component_type<selfcoordnum>("self-coordination number", "selfCoordNum");
add_component_type<groupcoordnum>("group-coordination number", "groupCoord");
add_component_type<angle>("angle", "angle");
add_component_type<dipole_angle>("dipole angle", "dipoleAngle");
add_component_type<dihedral>("dihedral", "dihedral");
add_component_type<h_bond>("hydrogen bond", "hBond");
if (proxy->check_atom_name_selections_available() == COLVARS_OK) {
add_component_type<alpha_angles>("alpha helix", "alpha");
add_component_type<dihedPC>("dihedral principal component", "dihedralPC");
}
add_component_type<orientation>("orientation", "orientation");
add_component_type<orientation_angle>("orientation angle", "orientationAngle");
add_component_type<orientation_proj>("orientation projection", "orientationProj");
add_component_type<tilt>("tilt", "tilt");
add_component_type<spin_angle>("spin angle", "spinAngle");
add_component_type<rmsd>("RMSD", "rmsd");
add_component_type<gyration>("radius of gyration", "gyration");
add_component_type<inertia>("moment of inertia", "inertia");
add_component_type<inertia_z>("moment of inertia around an axis", "inertiaZ");
add_component_type<eigenvector>("eigenvector", "eigenvector");
add_component_type<alch_lambda>("alchemical coupling parameter", "alchLambda");
add_component_type<alch_Flambda>("force on alchemical coupling parameter", "alchFLambda");
add_component_type<aspath>("arithmetic path collective variables (s)", "aspath");
add_component_type<azpath>("arithmetic path collective variables (z)", "azpath");
add_component_type<gspath>("geometrical path collective variables (s)", "gspath");
add_component_type<gzpath>("geometrical path collective variables (z)", "gzpath");
add_component_type<linearCombination>("linear combination of other collective variables", "linearCombination");
add_component_type<gspathCV>("geometrical path collective variables (s) for other CVs", "gspathCV");
add_component_type<gzpathCV>("geometrical path collective variables (z) for other CVs", "gzpathCV");
add_component_type<aspathCV>("arithmetic path collective variables (s) for other CVs", "aspathCV");
add_component_type<azpathCV>("arithmetic path collective variables (s) for other CVs", "azpathCV");
add_component_type<euler_phi>("euler phi angle of the optimal orientation", "eulerPhi");
add_component_type<euler_psi>("euler psi angle of the optimal orientation", "eulerPsi");
add_component_type<euler_theta>("euler theta angle of the optimal orientation", "eulerTheta");
#ifdef LEPTON
add_component_type<customColvar>("CV with support of the Lepton custom function", "customColvar");
#endif
add_component_type<neuralNetwork>("neural network CV for other CVs", "neuralNetwork");
if (proxy->check_volmaps_available() == COLVARS_OK) {
add_component_type<map_total>("total value of atomic map", "mapTotal");
}
}
int colvar::init_components(std::string const &conf) int colvar::init_components(std::string const &conf)
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
size_t i = 0, j = 0; size_t i = 0, j = 0;
// in the non-C++11 case, the components are initialized directly by init_components_type; if (global_cvc_map.empty()) {
// in the C++11 case, the components are stored in the global_cvc_map at first define_component_types();
// by init_components_type, and then the map is iterated to initialize all components. }
error_code |= init_components_type<distance>(conf, "distance", "distance");
error_code |= init_components_type<distance_vec>(conf, "distance vector", "distanceVec");
error_code |= init_components_type<cartesian>(conf, "Cartesian coordinates", "cartesian");
error_code |= init_components_type<distance_dir>(conf, "distance vector "
"direction", "distanceDir");
error_code |= init_components_type<distance_z>(conf, "distance projection "
"on an axis", "distanceZ");
error_code |= init_components_type<distance_xy>(conf, "distance projection "
"on a plane", "distanceXY");
error_code |= init_components_type<polar_theta>(conf, "spherical polar angle theta",
"polarTheta");
error_code |= init_components_type<polar_phi>(conf, "spherical azimuthal angle phi",
"polarPhi");
error_code |= init_components_type<distance_inv>(conf, "average distance "
"weighted by inverse power", "distanceInv");
error_code |= init_components_type<distance_pairs>(conf, "N1xN2-long vector "
"of pairwise distances", "distancePairs");
error_code |= init_components_type<dipole_magnitude>(conf, "dipole magnitude",
"dipoleMagnitude");
error_code |= init_components_type<coordnum>(conf, "coordination "
"number", "coordNum");
error_code |= init_components_type<selfcoordnum>(conf, "self-coordination "
"number", "selfCoordNum");
error_code |= init_components_type<groupcoordnum>(conf, "group-coordination "
"number", "groupCoord");
error_code |= init_components_type<angle>(conf, "angle", "angle");
error_code |= init_components_type<dipole_angle>(conf, "dipole angle", "dipoleAngle");
error_code |= init_components_type<dihedral>(conf, "dihedral", "dihedral");
error_code |= init_components_type<h_bond>(conf, "hydrogen bond", "hBond");
error_code |= init_components_type<alpha_angles>(conf, "alpha helix", "alpha");
error_code |= init_components_type<dihedPC>(conf, "dihedral "
"principal component", "dihedralPC");
error_code |= init_components_type<orientation>(conf, "orientation", "orientation");
error_code |= init_components_type<orientation_angle>(conf, "orientation "
"angle", "orientationAngle");
error_code |= init_components_type<orientation_proj>(conf, "orientation "
"projection", "orientationProj");
error_code |= init_components_type<tilt>(conf, "tilt", "tilt");
error_code |= init_components_type<spin_angle>(conf, "spin angle", "spinAngle");
error_code |= init_components_type<rmsd>(conf, "RMSD", "rmsd");
error_code |= init_components_type<gyration>(conf, "radius of "
"gyration", "gyration");
error_code |= init_components_type<inertia>(conf, "moment of "
"inertia", "inertia");
error_code |= init_components_type<inertia_z>(conf, "moment of inertia around an axis", "inertiaZ");
error_code |= init_components_type<eigenvector>(conf, "eigenvector", "eigenvector");
error_code |= init_components_type<alch_lambda>(conf, "alchemical coupling parameter", "alchLambda");
error_code |= init_components_type<alch_Flambda>(conf, "force on alchemical coupling parameter", "alchFLambda");
error_code |= init_components_type<gspath>(conf, "geometrical path collective variables (s)", "gspath");
error_code |= init_components_type<gzpath>(conf, "geometrical path collective variables (z)", "gzpath");
error_code |= init_components_type<linearCombination>(conf, "linear combination of other collective variables", "linearCombination");
error_code |= init_components_type<gspathCV>(conf, "geometrical path collective variables (s) for other CVs", "gspathCV");
error_code |= init_components_type<gzpathCV>(conf, "geometrical path collective variables (z) for other CVs", "gzpathCV");
error_code |= init_components_type<aspathCV>(conf, "arithmetic path collective variables (s) for other CVs", "aspathCV");
error_code |= init_components_type<azpathCV>(conf, "arithmetic path collective variables (s) for other CVs", "azpathCV");
error_code |= init_components_type<euler_phi>(conf, "euler phi angle of the optimal orientation", "eulerPhi");
error_code |= init_components_type<euler_psi>(conf, "euler psi angle of the optimal orientation", "eulerPsi");
error_code |= init_components_type<euler_theta>(conf, "euler theta angle of the optimal orientation", "eulerTheta");
#ifdef LEPTON
error_code |= init_components_type<customColvar>(conf, "CV with support of the lepton custom function", "customColvar");
#endif
error_code |= init_components_type<neuralNetwork>(conf, "neural network CV for other CVs", "NeuralNetwork");
error_code |= init_components_type<map_total>(conf, "total value of atomic map", "mapTotal");
#if (__cplusplus >= 201103L)
// iterate over all available CVC in the map // iterate over all available CVC in the map
for (auto it = global_cvc_map.begin(); it != global_cvc_map.end(); ++it) { for (auto it = global_cvc_map.begin(); it != global_cvc_map.end(); ++it) {
error_code |= init_components_type_from_global_map(conf, it->first.c_str()); error_code |= init_components_type(conf, it->first.c_str());
// TODO: is it better to check the error code here? // TODO: is it better to check the error code here?
if (error_code != COLVARS_OK) { if (error_code != COLVARS_OK) {
cvm::log("Failed to initialize " + it->first + " with the following configuration:\n"); cvm::log("Failed to initialize " + it->first + " with the following configuration:\n");
cvm::log(conf); cvm::log(conf);
// TODO: should it stop here? // TODO: should it stop here?
break;
} }
} }
#endif
if (!cvcs.size() || (error_code != COLVARS_OK)) { if (!cvcs.size()) {
cvm::error("Error: no valid components were provided " std::string msg("Error: no valid components were provided for this collective variable.\n");
"for this collective variable.\n", msg += "Currently available component types are: \n";
COLVARS_INPUT_ERROR); for (auto it = global_cvc_desc_map.begin(); it != global_cvc_desc_map.end(); ++it) {
return COLVARS_INPUT_ERROR; msg += " " + it->first + " -- " + it->second + "\n";
}
msg += "\nPlease note that some of the above types may still be unavailable, irrespective of this error.\n";
error_code |= cvm::error(msg, COLVARS_INPUT_ERROR);
} }
// Check for uniqueness of CVC names (esp. if user-provided) // Check for uniqueness of CVC names (esp. if user-provided)
for (i = 0; i < cvcs.size(); i++) { for (i = 0; i < cvcs.size(); i++) {
for (j = i+1; j < cvcs.size(); j++) { for (j = i + 1; j < cvcs.size(); j++) {
if (cvcs[i]->name == cvcs[j]->name) { if (cvcs[i]->name == cvcs[j]->name) {
cvm::error("Components " + cvm::to_str(i) + " and " + cvm::to_str(j) +\ error_code |= cvm::error("Components " + cvm::to_str(i) + " and " + cvm::to_str(j) +
" cannot have the same name \"" + cvcs[i]->name+ "\".\n", COLVARS_INPUT_ERROR); " cannot have the same name \"" + cvcs[i]->name + "\".\n",
return COLVARS_INPUT_ERROR; COLVARS_INPUT_ERROR);
} }
} }
} }
n_active_cvcs = cvcs.size(); if (error_code == COLVARS_OK) {
// Store list of children cvcs for dependency checking purposes
// Store list of children cvcs for dependency checking purposes for (i = 0; i < cvcs.size(); i++) {
for (i = 0; i < cvcs.size(); i++) { add_child(cvcs[i].get());
add_child(cvcs[i]); }
// By default all CVCs are active at the start
n_active_cvcs = cvcs.size();
cvm::log("All components initialized.\n");
} }
cvm::log("All components initialized.\n"); return error_code;
return COLVARS_OK;
} }
@ -1220,7 +1216,7 @@ int colvar::init_dependencies() {
// Initialize feature_states for each instance // Initialize feature_states for each instance
feature_states.reserve(f_cv_ntot); feature_states.reserve(f_cv_ntot);
for (i = 0; i < f_cv_ntot; i++) { for (i = feature_states.size(); i < f_cv_ntot; i++) {
feature_states.push_back(feature_state(true, false)); feature_states.push_back(feature_state(true, false));
// Most features are available, so we set them so // Most features are available, so we set them so
// and list exceptions below // and list exceptions below
@ -1283,14 +1279,10 @@ colvar::~colvar()
// for dependency purposes // for dependency purposes
remove_all_children(); remove_all_children();
for (std::vector<cvc *>::reverse_iterator ci = cvcs.rbegin(); for (auto ci = cvcs.rbegin(); ci != cvcs.rend(); ++ci) {
ci != cvcs.rend(); // Clear all children of this cvc (i.e. its atom groups), because the cvc base class destructor
++ci) { // can't do it early enough and we don't want to have each cvc derived class do it separately
// clear all children of this cvc (i.e. its atom groups)
// because the cvc base class destructor can't do it early enough
// and we don't want to have each cvc derived class do it separately
(*ci)->remove_all_children(); (*ci)->remove_all_children();
delete *ci;
} }
cvcs.clear(); cvcs.clear();
@ -1512,6 +1504,7 @@ int colvar::collect_cvc_values()
cvm::to_str(x, cvm::cv_width, cvm::cv_prec)+".\n"); cvm::to_str(x, cvm::cv_width, cvm::cv_prec)+".\n");
if (after_restart) { if (after_restart) {
x_old = x_restart;
if (cvm::proxy->simulation_running()) { if (cvm::proxy->simulation_running()) {
cvm::real const jump2 = dist2(x, x_restart) / (width*width); cvm::real const jump2 = dist2(x, x_restart) / (width*width);
if (jump2 > 0.25) { if (jump2 > 0.25) {
@ -1555,12 +1548,12 @@ int colvar::calc_cvc_gradients(int first_cvc, size_t num_cvcs)
(cvcs[i])->debug_gradients(); (cvcs[i])->debug_gradients();
} }
cvm::decrease_depth();
if (cvm::debug()) if (cvm::debug())
cvm::log("Done calculating gradients of colvar \""+this->name+"\".\n"); cvm::log("Done calculating gradients of colvar \""+this->name+"\".\n");
} }
cvm::decrease_depth();
return COLVARS_OK; return COLVARS_OK;
} }
@ -1706,12 +1699,13 @@ int colvar::calc_colvar_properties()
// Do the same if no simulation is running (eg. VMD postprocessing) // Do the same if no simulation is running (eg. VMD postprocessing)
if ((cvm::step_relative() == 0 && !after_restart) || x_ext.type() == colvarvalue::type_notset || !cvm::proxy->simulation_running()) { if ((cvm::step_relative() == 0 && !after_restart) || x_ext.type() == colvarvalue::type_notset || !cvm::proxy->simulation_running()) {
x_ext = x; x_ext = x;
cvm::log("Initializing extended coordinate to colvar value.\n");
if (is_enabled(f_cv_reflecting_lower_boundary) && x_ext < lower_boundary) { if (is_enabled(f_cv_reflecting_lower_boundary) && x_ext < lower_boundary) {
cvm::log("Warning: initializing extended coordinate to reflective lower boundary, as colvar value is below."); cvm::log("Warning: initializing extended coordinate to reflective lower boundary, as colvar value is below.\n");
x_ext = lower_boundary; x_ext = lower_boundary;
} }
if (is_enabled(f_cv_reflecting_upper_boundary) && x_ext > upper_boundary) { if (is_enabled(f_cv_reflecting_upper_boundary) && x_ext > upper_boundary) {
cvm::log("Warning: initializing extended coordinate to reflective upper boundary, as colvar value is above."); cvm::log("Warning: initializing extended coordinate to reflective upper boundary, as colvar value is above.\n");
x_ext = upper_boundary; x_ext = upper_boundary;
} }
@ -1721,8 +1715,18 @@ int colvar::calc_colvar_properties()
// Special case of a repeated timestep (eg. multiple NAMD "run" statements) // Special case of a repeated timestep (eg. multiple NAMD "run" statements)
// revert values of the extended coordinate and velocity prior to latest integration // revert values of the extended coordinate and velocity prior to latest integration
if (cvm::proxy->simulation_running() && cvm::step_relative() == prev_timestep) { if (cvm::proxy->simulation_running() && cvm::step_relative() == prev_timestep) {
x_ext = prev_x_ext; // Detect jumps due to discrete changes in coordinates (eg. in replica exchange schemes)
v_ext = prev_v_ext; cvm::real const jump2 = dist2(x, x_old) / (width*width);
if (jump2 > 0.25) {
cvm::log("Detected discrete jump in colvar value from "
+ cvm::to_str(x_old) + " to " + cvm::to_str(x) + ".\n");
cvm::log("Reinitializing extended coordinate to colvar value.\n");
x_ext = x;
} else {
cvm::log("Reinitializing extended coordinate to last value.\n");
x_ext = prev_x_ext;
v_ext = prev_v_ext;
}
} }
// report the restraint center as "value" // report the restraint center as "value"
// These position and velocities come from integration at the _previous timestep_ in update_forces_energy() // These position and velocities come from integration at the _previous timestep_ in update_forces_energy()
@ -1830,9 +1834,11 @@ void colvar::update_extended_Lagrangian()
f += fb_actual; f += fb_actual;
} }
fr = f; // fr: bias force on extended variable (without harmonic spring), for output in trajectory
// External force has been scaled for a 1-timestep impulse, scale it back because we will fr = f;
// integrate it with the colvar's own timestep factor
// External force has been scaled for an inner-timestep impulse (for the back-end integrator)
// here we scale it back because this integrator uses only the outer (long) timestep
f_ext = f / cvm::real(time_step_factor); f_ext = f / cvm::real(time_step_factor);
colvarvalue f_system(fr.type()); // force exterted by the system on the extended DOF colvarvalue f_system(fr.type()); // force exterted by the system on the extended DOF
@ -1845,15 +1851,14 @@ void colvar::update_extended_Lagrangian()
} else { } else {
// the total force is applied to the fictitious mass, while the // the total force is applied to the fictitious mass, while the
// atoms only feel the harmonic force + wall force // atoms only feel the harmonic force + wall force
// fr: bias force on extended variable (without harmonic spring), for output in trajectory
// f_ext: total force on extended variable (including harmonic spring) // f_ext: total force on extended variable (including harmonic spring)
// f: - initially, external biasing force // f: - initially, external biasing force
// - after this code block, colvar force to be applied to atomic coordinates // - after this code block, colvar force to be applied to atomic coordinates
// ie. spring force (fb_actual will be added just below) // ie. spring force (fb_actual will be added just below)
f_system = (-0.5 * ext_force_k) * this->dist2_lgrad(x_ext, x); f_system = (-0.5 * ext_force_k) * this->dist2_lgrad(x_ext, x);
f = -1.0 * f_system; f = -1.0 * f_system;
// Coupling force is a slow force, to be applied to atomic coords impulse-style // Coupling force will be applied to atomic coords impulse-style
// over a single MD timestep // over an inner timestep of the back-end integrator
f *= cvm::real(time_step_factor); f *= cvm::real(time_step_factor);
} }
f_ext += f_system; f_ext += f_system;
@ -1873,34 +1878,57 @@ void colvar::update_extended_Lagrangian()
prev_x_ext = x_ext; prev_x_ext = x_ext;
prev_v_ext = v_ext; prev_v_ext = v_ext;
// leapfrog: starting from x_i, f_i, v_(i-1/2) // BAOA (GSD) integrator as formulated in https://doi.org/10.1021/acs.jctc.2c00585
v_ext += (0.5 * dt) * f_ext / ext_mass; // starting from x_t, f_t, v_(t-1/2)
// Because of leapfrog, kinetic energy at time i is approximate // Variation: the velocity step is split in two to estimate the kinetic energy at time t
// so this is more of a "BBAOA" scheme: a rearranged BAOAB where the second B is deferred
// to the next time step for implementation reasons (waiting for the force calculation)
// [B] Eq. (10a) split into two half-steps
// would reduce to leapfrog when gamma = 0 if this was the reported velocity
v_ext += 0.5 * dt * f_ext / ext_mass;
// Kinetic energy at t
kinetic_energy = 0.5 * ext_mass * v_ext * v_ext; kinetic_energy = 0.5 * ext_mass * v_ext * v_ext;
// Potential energy at t
potential_energy = 0.5 * ext_force_k * this->dist2(x_ext, x); potential_energy = 0.5 * ext_force_k * this->dist2(x_ext, x);
// leap to v_(i+1/2)
// Total energy will lag behind position by one timestep
// (current kinetic energy is not accessible before the next force calculation)
v_ext += 0.5 * dt * f_ext / ext_mass;
// Final v_ext lags behind x_ext by half a timestep
// [A] Half step in position (10b)
x_ext += dt * v_ext / 2.0;
// [O] leap to v_(i+1/2) (10c)
if (is_enabled(f_cv_Langevin)) { if (is_enabled(f_cv_Langevin)) {
v_ext -= dt * ext_gamma * v_ext;
colvarvalue rnd(x); colvarvalue rnd(x);
rnd.set_random(); rnd.set_random();
v_ext += dt * ext_sigma * rnd / ext_mass; // ext_sigma has been computed at init time according to (10c)
v_ext = cvm::exp(- 1.0 * dt * ext_gamma) * v_ext + ext_sigma * rnd / ext_mass;
} }
v_ext += (0.5 * dt) * f_ext / ext_mass; // [A] Second half step in position (10d)
x_ext += dt * v_ext; x_ext += dt * v_ext / 2.0;
cvm::real delta = 0; // Length of overshoot past either reflecting boundary cvm::real delta = 0; // Length of overshoot past either reflecting boundary
if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) || if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) { (is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) {
// Reflect arrival position
x_ext -= 2.0 * delta; x_ext -= 2.0 * delta;
v_ext *= -1.0; // Bounce happened on average at t+1/2 -> reflect velocity at t+1/2
if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) || v_ext = -0.5 * (prev_v_ext + v_ext);
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) { if ((is_enabled(f_cv_reflecting_lower_boundary) && (x_ext - lower_boundary) < 0.0) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (x_ext - upper_boundary) > 0.0)) {
cvm::error("Error: extended coordinate value " + cvm::to_str(x_ext) + " is still outside boundaries after reflection.\n"); cvm::error("Error: extended coordinate value " + cvm::to_str(x_ext) + " is still outside boundaries after reflection.\n");
} }
} }
x_ext.apply_constraints(); x_ext.apply_constraints();
this->wrap(x_ext); this->wrap(x_ext);
if (is_enabled(f_cv_external)) { if (is_enabled(f_cv_external)) {
// Colvar value is constrained to the extended value // Colvar value is constrained to the extended value
x = x_ext; x = x_ext;
@ -1914,9 +1942,8 @@ int colvar::end_of_step()
if (cvm::debug()) if (cvm::debug())
cvm::log("End of step for colvar \""+this->name+"\".\n"); cvm::log("End of step for colvar \""+this->name+"\".\n");
if (is_enabled(f_cv_fdiff_velocity)) { // Used for fdiff_velocity and for detecting jumps for extended Lagrangian colvars
x_old = x; x_old = x;
}
if (is_enabled(f_cv_subtract_applied_force)) { if (is_enabled(f_cv_subtract_applied_force)) {
f_old = f; f_old = f;
@ -2256,44 +2283,65 @@ void colvar::wrap(colvarvalue &x_unwrapped) const
std::istream & colvar::read_state(std::istream &is) std::istream & colvar::read_state(std::istream &is)
{ {
std::streampos const start_pos = is.tellg(); auto const start_pos = is.tellg();
std::string conf; std::string conf;
if ( !(is >> colvarparse::read_block("colvar", &conf)) ) { if ( !(is >> colvarparse::read_block("colvar", &conf)) ||
(check_matching_state(conf) != COLVARS_OK) ) {
// this is not a colvar block // this is not a colvar block
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
return is; return is;
} }
{ if (!matching_state) {
std::string check_name = ""; // No errors reading, but this state is not for this colvar; rewind
get_keyval(conf, "name", check_name, is.seekg(start_pos);
std::string(""), colvarparse::parse_silent); return is;
if (check_name.size() == 0) {
cvm::error("Error: Collective variable in the "
"restart file without any identifier.\n", COLVARS_INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
if (check_name != name) {
if (cvm::debug()) {
cvm::log("Ignoring state of colvar \""+check_name+
"\": this colvar is named \""+name+"\".\n");
}
is.seekg(start_pos, std::ios::beg);
return is;
}
} }
if (set_state_params(conf) != COLVARS_OK) {
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
}
return is;
}
int colvar::check_matching_state(std::string const &conf)
{
std::string check_name = "";
get_keyval(conf, "name", check_name, std::string(""), colvarparse::parse_silent);
if (check_name.size() == 0) {
return cvm::error("Error: Collective variable in the "
"state file without any identifier.\n", COLVARS_INPUT_ERROR);
}
if (check_name != name) {
if (cvm::debug()) {
cvm::log("Ignoring state of colvar \""+check_name+
"\": this colvar is named \""+name+"\".\n");
}
matching_state = false;
} else {
matching_state = true;
}
return COLVARS_OK;
}
int colvar::set_state_params(std::string const &conf)
{
int error_code = COLVARS_OK;
if ( !(get_keyval(conf, "x", x, x, colvarparse::parse_silent)) ) { if ( !(get_keyval(conf, "x", x, x, colvarparse::parse_silent)) ) {
cvm::log("Error: restart file does not contain " error_code |= cvm::error("Error: restart file does not contain "
"the value of the colvar \""+ "the value of the colvar \""+
name+"\" .\n"); name+"\" .\n", COLVARS_INPUT_ERROR);
} else { } else {
cvm::log("Restarting collective variable \""+name+"\" from value: "+ cvm::log("Restarting collective variable \""+name+"\" from value: "+
cvm::to_str(x)+"\n"); cvm::to_str(x)+"\n");
@ -2306,9 +2354,10 @@ std::istream & colvar::read_state(std::istream &is)
colvarvalue(x.type()), colvarparse::parse_silent)) || colvarvalue(x.type()), colvarparse::parse_silent)) ||
!(get_keyval(conf, "extended_v", v_ext, !(get_keyval(conf, "extended_v", v_ext,
colvarvalue(x.type()), colvarparse::parse_silent)) ) { colvarvalue(x.type()), colvarparse::parse_silent)) ) {
cvm::log("Error: restart file does not contain " error_code |= cvm::error("Error: restart file does not contain "
"\"extended_x\" or \"extended_v\" for the colvar \""+ "\"extended_x\" or \"extended_v\" for the colvar \""+
name+"\", but you requested \"extendedLagrangian\".\n"); name+"\", but you requested \"extendedLagrangian\".\n",
COLVARS_INPUT_ERROR);
} }
x_reported = x_ext; x_reported = x_ext;
} else { } else {
@ -2319,9 +2368,10 @@ std::istream & colvar::read_state(std::istream &is)
if ( !(get_keyval(conf, "v", v_fdiff, if ( !(get_keyval(conf, "v", v_fdiff,
colvarvalue(x.type()), colvarparse::parse_silent)) ) { colvarvalue(x.type()), colvarparse::parse_silent)) ) {
cvm::log("Error: restart file does not contain " error_code |= cvm::error("Error: restart file does not contain "
"the velocity for the colvar \""+ "the velocity for the colvar \""+
name+"\", but you requested \"outputVelocity\".\n"); name+"\", but you requested \"outputVelocity\".\n",
COLVARS_INPUT_ERROR);
} }
if (is_enabled(f_cv_extended_Lagrangian)) { if (is_enabled(f_cv_extended_Lagrangian)) {
@ -2331,6 +2381,41 @@ std::istream & colvar::read_state(std::istream &is)
} }
} }
return error_code;
}
cvm::memory_stream &colvar::read_state(cvm::memory_stream &is)
{
auto const start_pos = is.tellg();
std::string key, data;
if (is >> key) {
if (key == "colvar") {
// Read a formatted config string, then read the state parameters from it
if (is >> data) {
if (set_state_params(data) == COLVARS_OK) {
return is;
}
}
}
}
auto const error_pos = is.tellg();
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
std::string error_msg("Error: in reading state data for colvar \"" + name + " at position " +
cvm::to_str(error_pos) + " in unformatted stream.\n");
if (key.size() && key != "colvar") {
error_msg += "; the keyword read was \"" + key + "\", but \"colvar\" was expected";
}
if (data.size()) {
error_msg += "; the configuration string read was not recognized";
}
error_msg += ".\n";
cvm::error(error_msg, COLVARS_INPUT_ERROR);
return is; return is;
} }
@ -2345,7 +2430,7 @@ std::istream & colvar::read_traj(std::istream &is)
cvm::log("Error: in reading the value of colvar \""+ cvm::log("Error: in reading the value of colvar \""+
this->name+"\" from trajectory.\n"); this->name+"\" from trajectory.\n");
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
return is; return is;
} }
@ -2385,10 +2470,23 @@ std::istream & colvar::read_traj(std::istream &is)
// ******************** OUTPUT FUNCTIONS ******************** // ******************** OUTPUT FUNCTIONS ********************
std::ostream & colvar::write_state(std::ostream &os) { std::ostream & colvar::write_state(std::ostream &os) const
{
os << "colvar {\n" << get_state_params() << "}\n\n";
os << "colvar {\n" if (runave_outfile.size() > 0) {
<< " name " << name << "\n" cvm::main()->proxy->flush_output_stream(runave_outfile);
}
return os;
}
std::string const colvar::get_state_params() const
{
std::ostringstream os;
os << " name " << name << "\n"
<< " x " << " x "
<< std::setprecision(cvm::cv_prec) << std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width) << std::setw(cvm::cv_width)
@ -2412,7 +2510,13 @@ std::ostream & colvar::write_state(std::ostream &os) {
<< v_reported << "\n"; << v_reported << "\n";
} }
os << "}\n\n"; return os.str();
}
cvm::memory_stream & colvar::write_state(cvm::memory_stream &os) const
{
os << std::string("colvar") << get_state_params();
if (runave_outfile.size() > 0) { if (runave_outfile.size() > 0) {
cvm::main()->proxy->flush_output_stream(runave_outfile); cvm::main()->proxy->flush_output_stream(runave_outfile);
@ -2875,14 +2979,11 @@ int colvar::calc_runave()
runave_variance *= 1.0 / cvm::real(runave_length-1); runave_variance *= 1.0 / cvm::real(runave_length-1);
if (runave_outfile.size() > 0) { if (runave_outfile.size() > 0) {
std::ostream &runave_os = proxy->output_stream(runave_outfile); std::ostream &runave_os =
runave_os << std::setw(cvm::it_width) << cvm::step_relative() proxy->output_stream(runave_outfile, "running average output file");
<< " " runave_os << std::setw(cvm::it_width) << cvm::step_relative() << " "
<< std::setprecision(cvm::cv_prec) << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << runave << " "
<< std::setw(cvm::cv_width) << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< runave << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< cvm::sqrt(runave_variance) << "\n"; << cvm::sqrt(runave_variance) << "\n";
} }
} }

View File

@ -10,12 +10,11 @@
#ifndef COLVAR_H #ifndef COLVAR_H
#define COLVAR_H #define COLVAR_H
#include <iostream>
#if (__cplusplus >= 201103L)
#include <map>
#include <functional> #include <functional>
#endif #include <list>
#include <iosfwd>
#include <map>
#include <memory>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
@ -91,7 +90,7 @@ public:
/// calculations, \link colvarbias_abf \endlink, it is used to /// calculations, \link colvarbias_abf \endlink, it is used to
/// calculate the grid spacing in the direction of this collective /// calculate the grid spacing in the direction of this collective
/// variable. /// variable.
cvm::real width; cvm::real width = 1.0;
/// \brief Implementation of the feature list for colvar /// \brief Implementation of the feature list for colvar
static std::vector<feature *> cv_features; static std::vector<feature *> cv_features;
@ -184,13 +183,13 @@ protected:
/// Previous velocity of the restraint center /// Previous velocity of the restraint center
colvarvalue prev_v_ext; colvarvalue prev_v_ext;
/// Mass of the restraint center /// Mass of the restraint center
cvm::real ext_mass; cvm::real ext_mass = 0.0;
/// Restraint force constant /// Restraint force constant
cvm::real ext_force_k; cvm::real ext_force_k = 0.0;
/// Friction coefficient for Langevin extended dynamics /// Friction coefficient for Langevin extended dynamics
cvm::real ext_gamma; cvm::real ext_gamma = 0.0;
/// Amplitude of Gaussian white noise for Langevin extended dynamics /// Amplitude of Gaussian white noise for Langevin extended dynamics
cvm::real ext_sigma; cvm::real ext_sigma = 0.0;
/// \brief Applied force on extended DOF, for output (unscaled if using MTS) /// \brief Applied force on extended DOF, for output (unscaled if using MTS)
colvarvalue fr; colvarvalue fr;
@ -224,14 +223,14 @@ public:
colvarvalue ft; colvarvalue ft;
/// Period, if this variable is periodic /// Period, if this variable is periodic
cvm::real period; cvm::real period = 0.0;
/// Center of wrapping, if this variable is periodic /// Center of wrapping, if this variable is periodic
cvm::real wrap_center; cvm::real wrap_center = 0.0;
/// \brief Expand the boundaries of multiples of width, to keep the /// \brief Expand the boundaries of multiples of width, to keep the
/// value always within range /// value always within range
bool expand_boundaries; bool expand_boundaries = false;
/// \brief Location of the lower boundary /// \brief Location of the lower boundary
colvarvalue lower_boundary; colvarvalue lower_boundary;
@ -252,6 +251,9 @@ public:
/// Main init function /// Main init function
int init(std::string const &conf); int init(std::string const &conf);
/// Populate the map of available CVC types
void define_component_types();
/// Parse the CVC configuration and allocate their data /// Parse the CVC configuration and allocate their data
int init_components(std::string const &conf); int init_components(std::string const &conf);
@ -271,17 +273,13 @@ public:
virtual int init_dependencies(); virtual int init_dependencies();
private: private:
/// Parse the CVC configuration for all components of a certain type
template<typename def_class_name> int init_components_type(std::string const & conf, /// Declare an available CVC type and its description, register them in the global map
char const *def_desc, template <typename def_class_name>
char const *def_config_key); void add_component_type(char const *description, char const *config_key);
#if (__cplusplus >= 201103L)
/// For the C++11 case, the names of all available components are /// Initialize any CVC objects matching the given key
/// registered in the global map at first, and then the CVC configuration int init_components_type(const std::string &conf, const char *config_key);
/// is parsed by this function
int init_components_type_from_global_map(const std::string& conf,
const char* def_config_key);
#endif
public: public:
@ -387,10 +385,10 @@ public:
protected: protected:
/// \brief Number of CVC objects with an active flag /// \brief Number of CVC objects with an active flag
size_t n_active_cvcs; size_t n_active_cvcs = 0;
/// Sum of square coefficients for active cvcs /// Sum of square coefficients for active cvcs
cvm::real active_cvc_square_norm; cvm::real active_cvc_square_norm = 0.0;
/// Update the sum of square coefficients for active cvcs /// Update the sum of square coefficients for active cvcs
void update_active_cvc_square_norm(); void update_active_cvc_square_norm();
@ -460,16 +458,35 @@ public:
/// Write a label to the trajectory file (comment line) /// Write a label to the trajectory file (comment line)
std::ostream & write_traj_label(std::ostream &os); std::ostream & write_traj_label(std::ostream &os);
/// Read the collective variable from a restart file /// Read the colvar's state from a formatted input stream
std::istream & read_state(std::istream &is); std::istream & read_state(std::istream &is);
/// Write the collective variable to a restart file
std::ostream & write_state(std::ostream &os); /// Read the colvar's state from an unformatted input stream
cvm::memory_stream & read_state(cvm::memory_stream &is);
/// Check the name of the bias vs. the given string, set the matching_state flag accordingly
int check_matching_state(std::string const &state_conf);
/// Read the values of colvar mutable data from a string (used by both versions of read_state())
int set_state_params(std::string const &state_conf);
/// Write the state information of this colvar in a block of text, suitable for later parsing
std::string const get_state_params() const;
/// Write the colvar's state to a formatted output stream
std::ostream & write_state(std::ostream &os) const;
/// Write the colvar's state to an unformatted output stream
cvm::memory_stream & write_state(cvm::memory_stream &os) const;
/// Write output files (if defined, e.g. in analysis mode) /// Write output files (if defined, e.g. in analysis mode)
int write_output_files(); int write_output_files();
protected: protected:
/// Flag used to tell if the state string being read is for this colvar
bool matching_state;
/// Previous value (to calculate velocities during analysis) /// Previous value (to calculate velocities during analysis)
colvarvalue x_old; colvarvalue x_old;
@ -554,15 +571,15 @@ protected:
/// Current value of the running average /// Current value of the running average
colvarvalue runave; colvarvalue runave;
/// Current value of the square deviation from the running average /// Current value of the square deviation from the running average
cvm::real runave_variance; cvm::real runave_variance = 0.0;
/// Calculate the running average and its standard deviation /// Calculate the running average and its standard deviation
int calc_runave(); int calc_runave();
/// If extended Lagrangian active: colvar kinetic energy /// If extended Lagrangian active: colvar kinetic energy
cvm::real kinetic_energy; cvm::real kinetic_energy = 0.0;
/// If extended Lagrangian active: colvar harmonic potential /// If extended Lagrangian active: colvar harmonic potential
cvm::real potential_energy; cvm::real potential_energy = 0.0;
public: public:
@ -601,8 +618,9 @@ public:
class dihedPC; class dihedPC;
class alch_lambda; class alch_lambda;
class alch_Flambda; class alch_Flambda;
class componentDisabled;
class CartesianBasedPath; class CartesianBasedPath;
class aspath;
class azpath;
class gspath; class gspath;
class gzpath; class gzpath;
class linearCombination; class linearCombination;
@ -626,21 +644,19 @@ public:
// components that do not handle any atoms directly // components that do not handle any atoms directly
class map_total; class map_total;
/// getter of the global cvc map
#if (__cplusplus >= 201103L)
/// A global mapping of cvc names to the cvc constructors /// A global mapping of cvc names to the cvc constructors
static const std::map<std::string, std::function<colvar::cvc* (const std::string& subcv_conf)>>& get_global_cvc_map() { static const std::map<std::string, std::function<colvar::cvc *()>> &get_global_cvc_map()
return global_cvc_map; {
return global_cvc_map;
} }
#endif
/// \brief function for sorting cvcs by their names /// \brief function for sorting cvcs by their names
static bool compare_cvc(const colvar::cvc* const i, const colvar::cvc* const j); static bool compare_cvc(const colvar::cvc* const i, const colvar::cvc* const j);
protected: protected:
/// \brief Array of \link colvar::cvc \endlink objects /// Array of components objects
std::vector<cvc *> cvcs; std::vector<std::shared_ptr<colvar::cvc>> cvcs;
/// \brief Flags to enable or disable cvcs at next colvar evaluation /// \brief Flags to enable or disable cvcs at next colvar evaluation
std::vector<bool> cvc_flags; std::vector<bool> cvc_flags;
@ -671,10 +687,11 @@ protected:
double dev_null; double dev_null;
#endif #endif
#if (__cplusplus >= 201103L)
/// A global mapping of cvc names to the cvc constructors /// A global mapping of cvc names to the cvc constructors
static std::map<std::string, std::function<colvar::cvc* (const std::string& subcv_conf)>> global_cvc_map; static std::map<std::string, std::function<colvar::cvc *()>> global_cvc_map;
#endif
/// A global mapping of cvc names to the corresponding descriptions
static std::map<std::string, std::string> global_cvc_desc_map;
/// Volmap numeric IDs, one for each CVC (-1 if not available) /// Volmap numeric IDs, one for each CVC (-1 if not available)
std::vector<int> volmap_ids_; std::vector<int> volmap_ids_;
@ -762,4 +779,3 @@ inline void colvar::reset_bias_force() {
} }
#endif #endif

View File

@ -7,126 +7,84 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <string> #include <string>
#include <algorithm>
namespace ArithmeticPathCV { namespace ArithmeticPathCV {
using std::vector; using std::vector;
enum path_sz {S, Z}; template <typename scalar_type>
template <typename element_type, typename scalar_type, path_sz path_type>
class ArithmeticPathBase { class ArithmeticPathBase {
public: public:
ArithmeticPathBase() {} ArithmeticPathBase() {}
virtual ~ArithmeticPathBase() {} ~ArithmeticPathBase() {}
virtual void initialize(size_t p_num_elements, size_t p_total_frames, double p_lambda, const vector<element_type>& p_element, const vector<double>& p_weights); void initialize(size_t p_num_elements, size_t p_total_frames, scalar_type p_lambda, const vector<scalar_type>& p_weights);
virtual void updateDistanceToReferenceFrames() = 0; void reComputeLambda(const vector<scalar_type>& rmsd_between_refs);
virtual void computeValue(); template <typename element_type>
virtual void computeDerivatives(); void computeValue(const vector<vector<element_type>>& frame_element_distances, scalar_type *s = nullptr, scalar_type *z = nullptr);
virtual void compute(); // can only be called after computeValue() for element-wise derivatives and store derivatives of i-th frame to dsdx and dzdx
virtual void reComputeLambda(const vector<scalar_type>& rmsd_between_refs); template <typename element_type>
void computeDerivatives(const vector<vector<element_type>>& frame_element_distances, vector<vector<element_type>> *dsdx = nullptr, vector<vector<element_type>> *dzdx = nullptr);
protected: protected:
scalar_type lambda; scalar_type lambda;
vector<scalar_type> weights; vector<scalar_type> squared_weights;
size_t num_elements; size_t num_elements;
size_t total_frames; size_t total_frames;
vector< vector<element_type> > frame_element_distances; vector<scalar_type> exponents;
scalar_type s; scalar_type max_exponent;
scalar_type z; scalar_type saved_exponent_sum;
vector<element_type> dsdx;
vector<element_type> dzdx;
private:
// intermediate variables
vector<scalar_type> s_numerator_frame;
vector<scalar_type> s_denominator_frame;
scalar_type numerator_s;
scalar_type denominator_s;
scalar_type normalization_factor; scalar_type normalization_factor;
scalar_type saved_s;
}; };
template <typename element_type, typename scalar_type, path_sz path_type> template <typename scalar_type>
void ArithmeticPathBase<element_type, scalar_type, path_type>::initialize(size_t p_num_elements, size_t p_total_frames, double p_lambda, const vector<element_type>& p_element, const vector<double>& p_weights) { void ArithmeticPathBase<scalar_type>::initialize(size_t p_num_elements, size_t p_total_frames, scalar_type p_lambda, const vector<scalar_type>& p_weights) {
lambda = p_lambda; lambda = p_lambda;
weights = p_weights; for (size_t i = 0; i < p_weights.size(); ++i) squared_weights.push_back(p_weights[i] * p_weights[i]);
num_elements = p_num_elements; num_elements = p_num_elements;
total_frames = p_total_frames; total_frames = p_total_frames;
frame_element_distances.resize(total_frames, p_element); exponents.resize(total_frames);
for (size_t i_frame = 0; i_frame < frame_element_distances.size(); ++i_frame) {
for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) {
frame_element_distances[i_frame][j_elem].reset();
}
}
s = scalar_type(0);
z = scalar_type(0);
dsdx = p_element;
dzdx = p_element;
s_numerator_frame.resize(total_frames, scalar_type(0));
s_denominator_frame.resize(total_frames, scalar_type(0));
numerator_s = scalar_type(0);
denominator_s = scalar_type(0);
normalization_factor = 1.0 / static_cast<scalar_type>(total_frames - 1); normalization_factor = 1.0 / static_cast<scalar_type>(total_frames - 1);
saved_s = scalar_type();
saved_exponent_sum = scalar_type();
max_exponent = scalar_type();
} }
template <typename element_type, typename scalar_type, path_sz path_type> template <typename scalar_type>
void ArithmeticPathBase<element_type, scalar_type, path_type>::computeValue() { template <typename element_type>
updateDistanceToReferenceFrames(); void ArithmeticPathBase<scalar_type>::computeValue(
numerator_s = scalar_type(0); const vector<vector<element_type>>& frame_element_distances,
denominator_s = scalar_type(0); scalar_type *s, scalar_type *z)
for (size_t i_frame = 0; i_frame < frame_element_distances.size(); ++i_frame) { {
scalar_type exponent_tmp = scalar_type(0); for (size_t i_frame = 0; i_frame < total_frames; ++i_frame) {
scalar_type exponent_tmp = scalar_type();
for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) { for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) {
exponent_tmp += weights[j_elem] * frame_element_distances[i_frame][j_elem] * weights[j_elem] * frame_element_distances[i_frame][j_elem]; exponent_tmp += squared_weights[j_elem] * frame_element_distances[i_frame][j_elem] * frame_element_distances[i_frame][j_elem];
} }
exponent_tmp = exponent_tmp * -1.0 * lambda; exponents[i_frame] = exponent_tmp * -1.0 * lambda;
// prevent underflow if the argument of cvm::exp is less than -708.4 if (i_frame == 0 || exponents[i_frame] > max_exponent) max_exponent = exponents[i_frame];
if (exponent_tmp > -708.4) {
exponent_tmp = cvm::exp(exponent_tmp);
} else {
exponent_tmp = 0;
}
numerator_s += static_cast<scalar_type>(i_frame) * exponent_tmp;
denominator_s += exponent_tmp;
s_numerator_frame[i_frame] = static_cast<scalar_type>(i_frame) * exponent_tmp;
s_denominator_frame[i_frame] = exponent_tmp;
} }
s = numerator_s / denominator_s * normalization_factor; scalar_type log_sum_exp_0 = scalar_type();
z = -1.0 / lambda * cvm::logn(denominator_s); scalar_type log_sum_exp_1 = scalar_type();
} for (size_t i_frame = 0; i_frame < total_frames; ++i_frame) {
exponents[i_frame] = cvm::exp(exponents[i_frame] - max_exponent);
template <typename element_type, typename scalar_type, path_sz path_type> log_sum_exp_0 += exponents[i_frame];
void ArithmeticPathBase<element_type, scalar_type, path_type>::compute() { log_sum_exp_1 += i_frame * exponents[i_frame];
computeValue(); }
computeDerivatives(); saved_exponent_sum = log_sum_exp_0;
} log_sum_exp_0 = max_exponent + cvm::logn(log_sum_exp_0);
log_sum_exp_1 = max_exponent + cvm::logn(log_sum_exp_1);
template <typename element_type, typename scalar_type, path_sz path_type> saved_s = normalization_factor * cvm::exp(log_sum_exp_1 - log_sum_exp_0);
void ArithmeticPathBase<element_type, scalar_type, path_type>::computeDerivatives() { if (s != nullptr) {
for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) { *s = saved_s;
element_type dsdxj_numerator_part1(dsdx[j_elem]); }
element_type dsdxj_numerator_part2(dsdx[j_elem]); if (z != nullptr) {
element_type dzdxj_numerator(dsdx[j_elem]); *z = -1.0 / lambda * log_sum_exp_0;
dsdxj_numerator_part1.reset();
dsdxj_numerator_part2.reset();
dzdxj_numerator.reset();
for (size_t i_frame = 0; i_frame < frame_element_distances.size(); ++i_frame) {
element_type derivative_tmp = -2.0 * lambda * weights[j_elem] * weights[j_elem] * frame_element_distances[i_frame][j_elem];
dsdxj_numerator_part1 += s_numerator_frame[i_frame] * derivative_tmp;
dsdxj_numerator_part2 += s_denominator_frame[i_frame] * derivative_tmp;
dzdxj_numerator += s_denominator_frame[i_frame] * derivative_tmp;
}
dsdxj_numerator_part1 *= denominator_s;
dsdxj_numerator_part2 *= numerator_s;
if ((dsdxj_numerator_part1 - dsdxj_numerator_part2).norm() < std::numeric_limits<scalar_type>::min()) {
dsdx[j_elem] = 0;
} else {
dsdx[j_elem] = (dsdxj_numerator_part1 - dsdxj_numerator_part2) / (denominator_s * denominator_s) * normalization_factor;
}
dzdx[j_elem] = -1.0 / lambda * dzdxj_numerator / denominator_s;
} }
} }
template <typename element_type, typename scalar_type, path_sz path_type> template <typename scalar_type>
void ArithmeticPathBase<element_type, scalar_type, path_type>::reComputeLambda(const vector<scalar_type>& rmsd_between_refs) { void ArithmeticPathBase<scalar_type>::reComputeLambda(const vector<scalar_type>& rmsd_between_refs) {
scalar_type mean_square_displacements = 0.0; scalar_type mean_square_displacements = 0.0;
for (size_t i_frame = 1; i_frame < total_frames; ++i_frame) { for (size_t i_frame = 1; i_frame < total_frames; ++i_frame) {
cvm::log(std::string("Distance between frame ") + cvm::to_str(i_frame) + " and " + cvm::to_str(i_frame + 1) + " is " + cvm::to_str(rmsd_between_refs[i_frame - 1]) + std::string("\n")); cvm::log(std::string("Distance between frame ") + cvm::to_str(i_frame) + " and " + cvm::to_str(i_frame + 1) + " is " + cvm::to_str(rmsd_between_refs[i_frame - 1]) + std::string("\n"));
@ -135,6 +93,45 @@ void ArithmeticPathBase<element_type, scalar_type, path_type>::reComputeLambda(c
mean_square_displacements /= scalar_type(total_frames - 1); mean_square_displacements /= scalar_type(total_frames - 1);
lambda = 1.0 / mean_square_displacements; lambda = 1.0 / mean_square_displacements;
} }
// frame-wise derivatives for frames using optimal rotation
template <typename scalar_type>
template <typename element_type>
void ArithmeticPathBase<scalar_type>::computeDerivatives(
const vector<vector<element_type>>& frame_element_distances,
vector<vector<element_type>> *dsdx,
vector<vector<element_type>> *dzdx)
{
vector<scalar_type> softmax_out, tmps;
softmax_out.reserve(total_frames);
tmps.reserve(total_frames);
for (size_t i_frame = 0; i_frame < total_frames; ++i_frame) {
softmax_out.push_back(exponents[i_frame] / saved_exponent_sum);
tmps.push_back(
(static_cast<scalar_type>(i_frame) -
static_cast<scalar_type>(total_frames - 1) * saved_s) *
normalization_factor);
}
if (dsdx != nullptr) {
for (size_t i_frame = 0; i_frame < total_frames; ++i_frame) {
for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) {
(*dsdx)[i_frame][j_elem] =
-2.0 * squared_weights[j_elem] * lambda *
frame_element_distances[i_frame][j_elem] *
softmax_out[i_frame] * tmps[i_frame];
}
}
}
if (dzdx != nullptr) {
for (size_t i_frame = 0; i_frame < total_frames; ++i_frame) {
for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) {
(*dzdx)[i_frame][j_elem] =
2.0 * squared_weights[j_elem] * softmax_out[i_frame] *
frame_element_distances[i_frame][j_elem];
}
}
}
}
} }
#endif // ARITHMETICPATHCV_H #endif // ARITHMETICPATHCV_H

View File

@ -8,12 +8,13 @@
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include "colvarmodule.h" #include "colvarmodule.h"
#include <vector>
#include <cmath>
#include <algorithm>
#include <string>
namespace GeometricPathCV { namespace GeometricPathCV {
@ -171,10 +172,14 @@ void GeometricPathBase<element_type, scalar_type, path_type>::determineClosestFr
sign = -1; sign = -1;
} }
if (cvm::fabs(static_cast<long>(frame_index[0]) - static_cast<long>(frame_index[1])) > 1) { if (cvm::fabs(static_cast<long>(frame_index[0]) - static_cast<long>(frame_index[1])) > 1) {
std::cout << "Warning: Geometrical pathCV relies on the assumption that the second closest frame is the neighbouring frame\n"; std::string message(
std::cout << " Please check your configuration or increase restraint on z(σ)\n"; "Warning: Geometrical pathCV relies on the assumption that the second closest frame is "
"the neighbouring frame\n"
" Please check your configuration or increase restraint on z(σ)\n");
for (size_t i_frame = 0; i_frame < frame_index.size(); ++i_frame) { for (size_t i_frame = 0; i_frame < frame_index.size(); ++i_frame) {
std::cout << "Frame index: " << frame_index[i_frame] << " ; optimal RMSD = " << frame_distances[frame_index[i_frame]] << "\n"; message += "Frame index: " + cvm::to_str(frame_index[i_frame]) +
" ; optimal RMSD = " + cvm::to_str(frame_distances[frame_index[i_frame]]) +
"\n";
} }
} }
min_frame_index_1 = frame_index[0]; // s_m min_frame_index_1 = frame_index[0]; // s_m

View File

@ -10,7 +10,6 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#if (__cplusplus >= 201103L)
#include "colvar_neuralnetworkcompute.h" #include "colvar_neuralnetworkcompute.h"
#include "colvarparse.h" #include "colvarparse.h"
#include "colvarproxy.h" #include "colvarproxy.h"
@ -272,9 +271,12 @@ std::vector<std::vector<double>> neuralNetworkCompute::multiply_matrix(const std
const size_t t = B[0].size(); const size_t t = B[0].size();
std::vector<std::vector<double>> C(m, std::vector<double>(t, 0.0)); std::vector<std::vector<double>> C(m, std::vector<double>(t, 0.0));
for (size_t i = 0; i < m; ++i) { for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < t; ++j) { for (size_t k = 0; k < n; ++k) {
for (size_t k = 0; k < n; ++k) { const auto tmp = A[i][k];
C[i][j] += A[i][k] * B[k][j]; auto& C_i = C[i];
auto& B_k = B[k];
for (size_t j = 0; j < t; ++j) {
C_i[j] += tmp * B_k[j];
} }
} }
} }
@ -306,5 +308,3 @@ void neuralNetworkCompute::compute() {
} }
} }
} }
#endif

View File

@ -7,7 +7,6 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
#if (__cplusplus >= 201103L)
#ifndef NEURALNETWORKCOMPUTE_H #ifndef NEURALNETWORKCOMPUTE_H
#define NEURALNETWORKCOMPUTE_H #define NEURALNETWORKCOMPUTE_H
@ -145,4 +144,3 @@ public:
} }
#endif #endif
#endif

View File

@ -0,0 +1,627 @@
#ifndef COLVAR_ROTATION_DERIVATIVE
#define COLVAR_ROTATION_DERIVATIVE
#include "colvartypes.h"
#include <type_traits>
#include <cstring>
/// \brief Helper function for loading the ia-th atom in the vector pos to x, y and z (C++11 SFINAE is used)
template <typename T, typename std::enable_if<std::is_same<T, cvm::atom_pos>::value, bool>::type = true>
inline void read_atom_coord(
size_t ia, const std::vector<T>& pos,
cvm::real* x, cvm::real* y, cvm::real* z) {
*x = pos[ia].x;
*y = pos[ia].y;
*z = pos[ia].z;
}
template <typename T, typename std::enable_if<std::is_same<T, cvm::atom>::value, bool>::type = true>
inline void read_atom_coord(
size_t ia, const std::vector<T>& pos,
cvm::real* x, cvm::real* y, cvm::real* z) {
*x = pos[ia].pos.x;
*y = pos[ia].pos.y;
*z = pos[ia].pos.z;
}
/// \brief Helper enum class for specifying options in rotation_derivative::prepare_derivative
enum class rotation_derivative_dldq {
/// Require the derivative of the leading eigenvalue with respect to the atom coordinats
use_dl = 1 << 0,
/// Require the derivative of the leading eigenvector with respect to the atom coordinats
use_dq = 1 << 1
};
inline constexpr rotation_derivative_dldq operator|(rotation_derivative_dldq Lhs, rotation_derivative_dldq Rhs) {
return static_cast<rotation_derivative_dldq>(
static_cast<std::underlying_type<rotation_derivative_dldq>::type>(Lhs) |
static_cast<std::underlying_type<rotation_derivative_dldq>::type>(Rhs));
}
inline constexpr bool operator&(rotation_derivative_dldq Lhs, rotation_derivative_dldq Rhs)
{
return (static_cast<std::underlying_type<rotation_derivative_dldq>::type>(Lhs) &
static_cast<std::underlying_type<rotation_derivative_dldq>::type>(Rhs));
}
/// \brief Helper class for calculating the derivative of rotation
template <typename T1, typename T2>
struct rotation_derivative {
static_assert(std::is_same<T1, cvm::atom_pos>::value || std::is_same<T1, cvm::atom>::value,
"class template rotation_derivative only supports cvm::atom_pos or cvm::atom types.");
static_assert(std::is_same<T2, cvm::atom_pos>::value || std::is_same<T2, cvm::atom>::value,
"class template rotation_derivative only supports cvm::atom_pos or cvm::atom types.");
/// \brief Reference to the rotation
const cvm::rotation &m_rot;
/// \brief Reference to the atom positions of group 1
const std::vector<T1> &m_pos1;
/// \brief Reference to the atom positions of group 2
const std::vector<T2> &m_pos2;
/// \brief Temporary variable that will be updated if prepare_derivative called
cvm::real tmp_Q0Q0[4][4];
cvm::real tmp_Q0Q0_L[4][4][4];
/*! @brief Constructor of the cvm::rotation::derivative class
* @param[in] rot The cvm::rotation object (must have called
* `calc_optimal_rotation` before calling
* `calc_derivative_wrt_group1` and
* `calc_derivative_wrt_group2`)
* @param[in] pos1 The atom positions of group 1
* @param[in] pos2 The atom positions of group 2
*/
rotation_derivative(
const cvm::rotation &rot,
const std::vector<T1> &pos1,
const std::vector<T2> &pos2):
m_rot(rot), m_pos1(pos1), m_pos2(pos2) {};
/*! @brief This function must be called before `calc_derivative_wrt_group1`
* and `calc_derivative_wrt_group2` in order to prepare the tmp_Q0Q0
* and tmp_Q0Q0_L.
* @param[in] require_dl_dq Require the calculation of the derivatives of L or/and Q
* with respect to atoms.
*/
void prepare_derivative(rotation_derivative_dldq require_dl_dq) {
if (require_dl_dq & rotation_derivative_dldq::use_dl) {
const auto &Q0 = m_rot.S_eigvec[0];
tmp_Q0Q0[0][0] = Q0[0] * Q0[0];
tmp_Q0Q0[0][1] = Q0[0] * Q0[1];
tmp_Q0Q0[0][2] = Q0[0] * Q0[2];
tmp_Q0Q0[0][3] = Q0[0] * Q0[3];
tmp_Q0Q0[1][0] = Q0[1] * Q0[0];
tmp_Q0Q0[1][1] = Q0[1] * Q0[1];
tmp_Q0Q0[1][2] = Q0[1] * Q0[2];
tmp_Q0Q0[1][3] = Q0[1] * Q0[3];
tmp_Q0Q0[2][0] = Q0[2] * Q0[0];
tmp_Q0Q0[2][1] = Q0[2] * Q0[1];
tmp_Q0Q0[2][2] = Q0[2] * Q0[2];
tmp_Q0Q0[2][3] = Q0[2] * Q0[3];
tmp_Q0Q0[3][0] = Q0[3] * Q0[0];
tmp_Q0Q0[3][1] = Q0[3] * Q0[1];
tmp_Q0Q0[3][2] = Q0[3] * Q0[2];
tmp_Q0Q0[3][3] = Q0[3] * Q0[3];
}
if (require_dl_dq & rotation_derivative_dldq::use_dq) {
const auto &Q0 = m_rot.S_eigvec[0];
const auto &Q1 = m_rot.S_eigvec[1];
const auto &Q2 = m_rot.S_eigvec[2];
const auto &Q3 = m_rot.S_eigvec[3];
cvm::real const L0 = m_rot.S_eigval[0];
cvm::real const L1 = m_rot.S_eigval[1];
cvm::real const L2 = m_rot.S_eigval[2];
cvm::real const L3 = m_rot.S_eigval[3];
tmp_Q0Q0_L[0][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[0] +
(Q2[0] * Q0[0]) / (L0-L2) * Q2[0] +
(Q3[0] * Q0[0]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[1] +
(Q2[0] * Q0[0]) / (L0-L2) * Q2[1] +
(Q3[0] * Q0[0]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[2] +
(Q2[0] * Q0[0]) / (L0-L2) * Q2[2] +
(Q3[0] * Q0[0]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[3] +
(Q2[0] * Q0[0]) / (L0-L2) * Q2[3] +
(Q3[0] * Q0[0]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[0] +
(Q2[0] * Q0[1]) / (L0-L2) * Q2[0] +
(Q3[0] * Q0[1]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[1] +
(Q2[0] * Q0[1]) / (L0-L2) * Q2[1] +
(Q3[0] * Q0[1]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[2] +
(Q2[0] * Q0[1]) / (L0-L2) * Q2[2] +
(Q3[0] * Q0[1]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[3] +
(Q2[0] * Q0[1]) / (L0-L2) * Q2[3] +
(Q3[0] * Q0[1]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[0] +
(Q2[0] * Q0[2]) / (L0-L2) * Q2[0] +
(Q3[0] * Q0[2]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[1] +
(Q2[0] * Q0[2]) / (L0-L2) * Q2[1] +
(Q3[0] * Q0[2]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[2] +
(Q2[0] * Q0[2]) / (L0-L2) * Q2[2] +
(Q3[0] * Q0[2]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[3] +
(Q2[0] * Q0[2]) / (L0-L2) * Q2[3] +
(Q3[0] * Q0[2]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[0] +
(Q2[0] * Q0[3]) / (L0-L2) * Q2[0] +
(Q3[0] * Q0[3]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[1] +
(Q2[0] * Q0[3]) / (L0-L2) * Q2[1] +
(Q3[0] * Q0[3]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[2] +
(Q2[0] * Q0[3]) / (L0-L2) * Q2[2] +
(Q3[0] * Q0[3]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[3] +
(Q2[0] * Q0[3]) / (L0-L2) * Q2[3] +
(Q3[0] * Q0[3]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[0] +
(Q2[1] * Q0[0]) / (L0-L2) * Q2[0] +
(Q3[1] * Q0[0]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[1] +
(Q2[1] * Q0[0]) / (L0-L2) * Q2[1] +
(Q3[1] * Q0[0]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[2] +
(Q2[1] * Q0[0]) / (L0-L2) * Q2[2] +
(Q3[1] * Q0[0]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[3] +
(Q2[1] * Q0[0]) / (L0-L2) * Q2[3] +
(Q3[1] * Q0[0]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[0] +
(Q2[1] * Q0[1]) / (L0-L2) * Q2[0] +
(Q3[1] * Q0[1]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[1] +
(Q2[1] * Q0[1]) / (L0-L2) * Q2[1] +
(Q3[1] * Q0[1]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[2] +
(Q2[1] * Q0[1]) / (L0-L2) * Q2[2] +
(Q3[1] * Q0[1]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[3] +
(Q2[1] * Q0[1]) / (L0-L2) * Q2[3] +
(Q3[1] * Q0[1]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[0] +
(Q2[1] * Q0[2]) / (L0-L2) * Q2[0] +
(Q3[1] * Q0[2]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[1] +
(Q2[1] * Q0[2]) / (L0-L2) * Q2[1] +
(Q3[1] * Q0[2]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[2] +
(Q2[1] * Q0[2]) / (L0-L2) * Q2[2] +
(Q3[1] * Q0[2]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[3] +
(Q2[1] * Q0[2]) / (L0-L2) * Q2[3] +
(Q3[1] * Q0[2]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[0] +
(Q2[1] * Q0[3]) / (L0-L2) * Q2[0] +
(Q3[1] * Q0[3]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[1] +
(Q2[1] * Q0[3]) / (L0-L2) * Q2[1] +
(Q3[1] * Q0[3]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[2] +
(Q2[1] * Q0[3]) / (L0-L2) * Q2[2] +
(Q3[1] * Q0[3]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[3] +
(Q2[1] * Q0[3]) / (L0-L2) * Q2[3] +
(Q3[1] * Q0[3]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[0] +
(Q2[2] * Q0[0]) / (L0-L2) * Q2[0] +
(Q3[2] * Q0[0]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[1] +
(Q2[2] * Q0[0]) / (L0-L2) * Q2[1] +
(Q3[2] * Q0[0]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[2] +
(Q2[2] * Q0[0]) / (L0-L2) * Q2[2] +
(Q3[2] * Q0[0]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[3] +
(Q2[2] * Q0[0]) / (L0-L2) * Q2[3] +
(Q3[2] * Q0[0]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[0] +
(Q2[2] * Q0[1]) / (L0-L2) * Q2[0] +
(Q3[2] * Q0[1]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[1] +
(Q2[2] * Q0[1]) / (L0-L2) * Q2[1] +
(Q3[2] * Q0[1]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[2] +
(Q2[2] * Q0[1]) / (L0-L2) * Q2[2] +
(Q3[2] * Q0[1]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[3] +
(Q2[2] * Q0[1]) / (L0-L2) * Q2[3] +
(Q3[2] * Q0[1]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[0] +
(Q2[2] * Q0[2]) / (L0-L2) * Q2[0] +
(Q3[2] * Q0[2]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[1] +
(Q2[2] * Q0[2]) / (L0-L2) * Q2[1] +
(Q3[2] * Q0[2]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[2] +
(Q2[2] * Q0[2]) / (L0-L2) * Q2[2] +
(Q3[2] * Q0[2]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[3] +
(Q2[2] * Q0[2]) / (L0-L2) * Q2[3] +
(Q3[2] * Q0[2]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[0] +
(Q2[2] * Q0[3]) / (L0-L2) * Q2[0] +
(Q3[2] * Q0[3]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[1] +
(Q2[2] * Q0[3]) / (L0-L2) * Q2[1] +
(Q3[2] * Q0[3]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[2] +
(Q2[2] * Q0[3]) / (L0-L2) * Q2[2] +
(Q3[2] * Q0[3]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[3] +
(Q2[2] * Q0[3]) / (L0-L2) * Q2[3] +
(Q3[2] * Q0[3]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[0] +
(Q2[3] * Q0[0]) / (L0-L2) * Q2[0] +
(Q3[3] * Q0[0]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[1] +
(Q2[3] * Q0[0]) / (L0-L2) * Q2[1] +
(Q3[3] * Q0[0]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[2] +
(Q2[3] * Q0[0]) / (L0-L2) * Q2[2] +
(Q3[3] * Q0[0]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[3] +
(Q2[3] * Q0[0]) / (L0-L2) * Q2[3] +
(Q3[3] * Q0[0]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[0] +
(Q2[3] * Q0[1]) / (L0-L2) * Q2[0] +
(Q3[3] * Q0[1]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[1] +
(Q2[3] * Q0[1]) / (L0-L2) * Q2[1] +
(Q3[3] * Q0[1]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[2] +
(Q2[3] * Q0[1]) / (L0-L2) * Q2[2] +
(Q3[3] * Q0[1]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[3] +
(Q2[3] * Q0[1]) / (L0-L2) * Q2[3] +
(Q3[3] * Q0[1]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[0] +
(Q2[3] * Q0[2]) / (L0-L2) * Q2[0] +
(Q3[3] * Q0[2]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[1] +
(Q2[3] * Q0[2]) / (L0-L2) * Q2[1] +
(Q3[3] * Q0[2]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[2] +
(Q2[3] * Q0[2]) / (L0-L2) * Q2[2] +
(Q3[3] * Q0[2]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[3] +
(Q2[3] * Q0[2]) / (L0-L2) * Q2[3] +
(Q3[3] * Q0[2]) / (L0-L3) * Q3[3];
tmp_Q0Q0_L[0][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[0] +
(Q2[3] * Q0[3]) / (L0-L2) * Q2[0] +
(Q3[3] * Q0[3]) / (L0-L3) * Q3[0];
tmp_Q0Q0_L[1][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[1] +
(Q2[3] * Q0[3]) / (L0-L2) * Q2[1] +
(Q3[3] * Q0[3]) / (L0-L3) * Q3[1];
tmp_Q0Q0_L[2][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[2] +
(Q2[3] * Q0[3]) / (L0-L2) * Q2[2] +
(Q3[3] * Q0[3]) / (L0-L3) * Q3[2];
tmp_Q0Q0_L[3][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[3] +
(Q2[3] * Q0[3]) / (L0-L2) * Q2[3] +
(Q3[3] * Q0[3]) / (L0-L3) * Q3[3];
}
}
/*! @brief Actual implementation of the derivative calculation
* @param[in] ds The derivative of matrix S with respect to an atom of
* either group 1 or group 2
* @param[out] dl0_out The output of derivative of L
* @param[out] dq0_out The output of derivative of Q
* @param[out] ds_out The output of derivative of overlap matrix S
*/
void calc_derivative_impl(
const cvm::rvector (&ds)[4][4],
cvm::rvector* const dl0_out,
cvm::vector1d<cvm::rvector>* const dq0_out,
cvm::matrix2d<cvm::rvector>* const ds_out) const {
if (ds_out != nullptr) {
// this code path is for debug_gradients, so not necessary to unroll the loop
*ds_out = cvm::matrix2d<cvm::rvector>(4, 4);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
(*ds_out)[i][j] = ds[i][j];
}
}
}
if (dl0_out != nullptr) {
/* manually loop unrolling of the following loop:
dl0_1.reset();
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
dl0_1 += Q0[i] * ds_1[i][j] * Q0[j];
}
}
*/
*dl0_out = tmp_Q0Q0[0][0] * ds[0][0] +
tmp_Q0Q0[0][1] * ds[0][1] +
tmp_Q0Q0[0][2] * ds[0][2] +
tmp_Q0Q0[0][3] * ds[0][3] +
tmp_Q0Q0[1][0] * ds[1][0] +
tmp_Q0Q0[1][1] * ds[1][1] +
tmp_Q0Q0[1][2] * ds[1][2] +
tmp_Q0Q0[1][3] * ds[1][3] +
tmp_Q0Q0[2][0] * ds[2][0] +
tmp_Q0Q0[2][1] * ds[2][1] +
tmp_Q0Q0[2][2] * ds[2][2] +
tmp_Q0Q0[2][3] * ds[2][3] +
tmp_Q0Q0[3][0] * ds[3][0] +
tmp_Q0Q0[3][1] * ds[3][1] +
tmp_Q0Q0[3][2] * ds[3][2] +
tmp_Q0Q0[3][3] * ds[3][3];
}
if (dq0_out != nullptr) {
// we can skip this check if a fixed-size array is used
if (dq0_out->size() != 4) dq0_out->resize(4);
/* manually loop unrolling of the following loop:
dq0_1.reset();
for (size_t p = 0; p < 4; p++) {
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
dq0_1[p] +=
(Q1[i] * ds_1[i][j] * Q0[j]) / (L0-L1) * Q1[p] +
(Q2[i] * ds_1[i][j] * Q0[j]) / (L0-L2) * Q2[p] +
(Q3[i] * ds_1[i][j] * Q0[j]) / (L0-L3) * Q3[p];
}
}
}
*/
(*dq0_out)[0] = tmp_Q0Q0_L[0][0][0] * ds[0][0] +
tmp_Q0Q0_L[0][0][1] * ds[0][1] +
tmp_Q0Q0_L[0][0][2] * ds[0][2] +
tmp_Q0Q0_L[0][0][3] * ds[0][3] +
tmp_Q0Q0_L[0][1][0] * ds[1][0] +
tmp_Q0Q0_L[0][1][1] * ds[1][1] +
tmp_Q0Q0_L[0][1][2] * ds[1][2] +
tmp_Q0Q0_L[0][1][3] * ds[1][3] +
tmp_Q0Q0_L[0][2][0] * ds[2][0] +
tmp_Q0Q0_L[0][2][1] * ds[2][1] +
tmp_Q0Q0_L[0][2][2] * ds[2][2] +
tmp_Q0Q0_L[0][2][3] * ds[2][3] +
tmp_Q0Q0_L[0][3][0] * ds[3][0] +
tmp_Q0Q0_L[0][3][1] * ds[3][1] +
tmp_Q0Q0_L[0][3][2] * ds[3][2] +
tmp_Q0Q0_L[0][3][3] * ds[3][3];
(*dq0_out)[1] = tmp_Q0Q0_L[1][0][0] * ds[0][0] +
tmp_Q0Q0_L[1][0][1] * ds[0][1] +
tmp_Q0Q0_L[1][0][2] * ds[0][2] +
tmp_Q0Q0_L[1][0][3] * ds[0][3] +
tmp_Q0Q0_L[1][1][0] * ds[1][0] +
tmp_Q0Q0_L[1][1][1] * ds[1][1] +
tmp_Q0Q0_L[1][1][2] * ds[1][2] +
tmp_Q0Q0_L[1][1][3] * ds[1][3] +
tmp_Q0Q0_L[1][2][0] * ds[2][0] +
tmp_Q0Q0_L[1][2][1] * ds[2][1] +
tmp_Q0Q0_L[1][2][2] * ds[2][2] +
tmp_Q0Q0_L[1][2][3] * ds[2][3] +
tmp_Q0Q0_L[1][3][0] * ds[3][0] +
tmp_Q0Q0_L[1][3][1] * ds[3][1] +
tmp_Q0Q0_L[1][3][2] * ds[3][2] +
tmp_Q0Q0_L[1][3][3] * ds[3][3];
(*dq0_out)[2] = tmp_Q0Q0_L[2][0][0] * ds[0][0] +
tmp_Q0Q0_L[2][0][1] * ds[0][1] +
tmp_Q0Q0_L[2][0][2] * ds[0][2] +
tmp_Q0Q0_L[2][0][3] * ds[0][3] +
tmp_Q0Q0_L[2][1][0] * ds[1][0] +
tmp_Q0Q0_L[2][1][1] * ds[1][1] +
tmp_Q0Q0_L[2][1][2] * ds[1][2] +
tmp_Q0Q0_L[2][1][3] * ds[1][3] +
tmp_Q0Q0_L[2][2][0] * ds[2][0] +
tmp_Q0Q0_L[2][2][1] * ds[2][1] +
tmp_Q0Q0_L[2][2][2] * ds[2][2] +
tmp_Q0Q0_L[2][2][3] * ds[2][3] +
tmp_Q0Q0_L[2][3][0] * ds[3][0] +
tmp_Q0Q0_L[2][3][1] * ds[3][1] +
tmp_Q0Q0_L[2][3][2] * ds[3][2] +
tmp_Q0Q0_L[2][3][3] * ds[3][3];
(*dq0_out)[3] = tmp_Q0Q0_L[3][0][0] * ds[0][0] +
tmp_Q0Q0_L[3][0][1] * ds[0][1] +
tmp_Q0Q0_L[3][0][2] * ds[0][2] +
tmp_Q0Q0_L[3][0][3] * ds[0][3] +
tmp_Q0Q0_L[3][1][0] * ds[1][0] +
tmp_Q0Q0_L[3][1][1] * ds[1][1] +
tmp_Q0Q0_L[3][1][2] * ds[1][2] +
tmp_Q0Q0_L[3][1][3] * ds[1][3] +
tmp_Q0Q0_L[3][2][0] * ds[2][0] +
tmp_Q0Q0_L[3][2][1] * ds[2][1] +
tmp_Q0Q0_L[3][2][2] * ds[2][2] +
tmp_Q0Q0_L[3][2][3] * ds[2][3] +
tmp_Q0Q0_L[3][3][0] * ds[3][0] +
tmp_Q0Q0_L[3][3][1] * ds[3][1] +
tmp_Q0Q0_L[3][3][2] * ds[3][2] +
tmp_Q0Q0_L[3][3][3] * ds[3][3];
}
}
/*! @brief Calculate the derivatives of S, the leading eigenvalue L and
* the leading eigenvector Q with respect to `m_pos1`
* @param[in] ia The index the of atom
* @param[out] dl0_1_out The output of derivative of L with respect to
* ia-th atom of group 1
* @param[out] dq0_1_out The output of derivative of Q with respect to
* ia-th atom of group 1
* @param[out] ds_1_out The output of derivative of overlap matrix S with
* respect to ia-th atom of group 1
*/
void calc_derivative_wrt_group1(
size_t ia, cvm::rvector* const dl0_1_out = nullptr,
cvm::vector1d<cvm::rvector>* const dq0_1_out = nullptr,
cvm::matrix2d<cvm::rvector>* const ds_1_out = nullptr) const {
if (dl0_1_out == nullptr && dq0_1_out == nullptr) return;
cvm::real a2x, a2y, a2z;
// we can get rid of the helper function read_atom_coord if C++17 (constexpr) is available
read_atom_coord(ia, m_pos2, &a2x, &a2y, &a2z);
cvm::rvector ds_1[4][4];
ds_1[0][0].set( a2x, a2y, a2z);
ds_1[1][0].set( 0.0, a2z, -a2y);
ds_1[0][1] = ds_1[1][0];
ds_1[2][0].set(-a2z, 0.0, a2x);
ds_1[0][2] = ds_1[2][0];
ds_1[3][0].set( a2y, -a2x, 0.0);
ds_1[0][3] = ds_1[3][0];
ds_1[1][1].set( a2x, -a2y, -a2z);
ds_1[2][1].set( a2y, a2x, 0.0);
ds_1[1][2] = ds_1[2][1];
ds_1[3][1].set( a2z, 0.0, a2x);
ds_1[1][3] = ds_1[3][1];
ds_1[2][2].set(-a2x, a2y, -a2z);
ds_1[3][2].set( 0.0, a2z, a2y);
ds_1[2][3] = ds_1[3][2];
ds_1[3][3].set(-a2x, -a2y, a2z);
calc_derivative_impl(ds_1, dl0_1_out, dq0_1_out, ds_1_out);
}
/*! @brief Calculate the derivatives of S, the leading eigenvalue L and
* the leading eigenvector Q with respect to `m_pos2`
* @param[in] ia The index the of atom
* @param[out] dl0_2_out The output of derivative of L with respect to
* ia-th atom of group 2
* @param[out] dq0_2_out The output of derivative of Q with respect to
* ia-th atom of group 2
* @param[out] ds_2_out The output of derivative of overlap matrix S with
* respect to ia-th atom of group 2
*/
void calc_derivative_wrt_group2(
size_t ia, cvm::rvector* const dl0_2_out = nullptr,
cvm::vector1d<cvm::rvector>* const dq0_2_out = nullptr,
cvm::matrix2d<cvm::rvector>* const ds_2_out = nullptr) const {
if (dl0_2_out == nullptr && dq0_2_out == nullptr) return;
cvm::real a1x, a1y, a1z;
// we can get rid of the helper function read_atom_coord if C++17 (constexpr) is available
read_atom_coord(ia, m_pos1, &a1x, &a1y, &a1z);
cvm::rvector ds_2[4][4];
ds_2[0][0].set( a1x, a1y, a1z);
ds_2[1][0].set( 0.0, -a1z, a1y);
ds_2[0][1] = ds_2[1][0];
ds_2[2][0].set( a1z, 0.0, -a1x);
ds_2[0][2] = ds_2[2][0];
ds_2[3][0].set(-a1y, a1x, 0.0);
ds_2[0][3] = ds_2[3][0];
ds_2[1][1].set( a1x, -a1y, -a1z);
ds_2[2][1].set( a1y, a1x, 0.0);
ds_2[1][2] = ds_2[2][1];
ds_2[3][1].set( a1z, 0.0, a1x);
ds_2[1][3] = ds_2[3][1];
ds_2[2][2].set(-a1x, a1y, -a1z);
ds_2[3][2].set( 0.0, a1z, a1y);
ds_2[2][3] = ds_2[3][2];
ds_2[3][3].set(-a1x, -a1y, a1z);
calc_derivative_impl(ds_2, dl0_2_out, dq0_2_out, ds_2_out);
}
};
/*! @brief Function for debugging gradients (allow using either
* std::vector<cvm::atom_pos> or std::vector<cvm::atom> for
* pos1 and pos2)
* @param[in] pos1 Atom positions of group 1
* @param[in] pos2 Atom positions of group 2
*/
template<typename T1, typename T2>
void debug_gradients(
cvm::rotation &rot,
const std::vector<T1> &pos1,
const std::vector<T2> &pos2) {
static_assert(std::is_same<T1, cvm::atom_pos>::value || std::is_same<T1, cvm::atom>::value, "");
static_assert(std::is_same<T2, cvm::atom_pos>::value || std::is_same<T2, cvm::atom>::value, "");
// eigenvalues and eigenvectors
cvm::real const L0 = rot.S_eigval[0];
cvm::real const L1 = rot.S_eigval[1];
cvm::real const L2 = rot.S_eigval[2];
cvm::real const L3 = rot.S_eigval[3];
cvm::quaternion const Q0(rot.S_eigvec[0]);
cvm::quaternion const Q1(rot.S_eigvec[1]);
cvm::quaternion const Q2(rot.S_eigvec[2]);
cvm::quaternion const Q3(rot.S_eigvec[3]);
cvm::log("L0 = "+cvm::to_str(L0, cvm::cv_width, cvm::cv_prec)+
", Q0 = "+cvm::to_str(Q0, cvm::cv_width, cvm::cv_prec)+
", Q0*Q0 = "+cvm::to_str(Q0.inner(Q0), cvm::cv_width, cvm::cv_prec)+
"\n");
cvm::log("L1 = "+cvm::to_str(L1, cvm::cv_width, cvm::cv_prec)+
", Q1 = "+cvm::to_str(Q1, cvm::cv_width, cvm::cv_prec)+
", Q0*Q1 = "+cvm::to_str(Q0.inner(Q1), cvm::cv_width, cvm::cv_prec)+
"\n");
cvm::log("L2 = "+cvm::to_str(L2, cvm::cv_width, cvm::cv_prec)+
", Q2 = "+cvm::to_str(Q2, cvm::cv_width, cvm::cv_prec)+
", Q0*Q2 = "+cvm::to_str(Q0.inner(Q2), cvm::cv_width, cvm::cv_prec)+
"\n");
cvm::log("L3 = "+cvm::to_str(L3, cvm::cv_width, cvm::cv_prec)+
", Q3 = "+cvm::to_str(Q3, cvm::cv_width, cvm::cv_prec)+
", Q0*Q3 = "+cvm::to_str(Q0.inner(Q3), cvm::cv_width, cvm::cv_prec)+
"\n");
rotation_derivative<T1, T2> deriv(rot, pos1, pos2);
cvm::rvector dl0_2;
cvm::vector1d<cvm::rvector> dq0_2(4);
cvm::matrix2d<cvm::rvector> ds_2;
#ifdef COLVARS_LAMMPS
MathEigen::Jacobi<cvm::real,
cvm::real[4],
cvm::real[4][4]> *ecalc =
reinterpret_cast<MathEigen::Jacobi<cvm::real,
cvm::real[4],
cvm::real[4][4]> *>(rot.jacobi);
#endif
deriv.prepare_derivative(rotation_derivative_dldq::use_dl | rotation_derivative_dldq::use_dq);
cvm::real S_new[4][4];
cvm::real S_new_eigval[4];
cvm::real S_new_eigvec[4][4];
for (size_t ia = 0; ia < pos2.size(); ++ia) {
// cvm::real const &a1x = pos1[ia].x;
// cvm::real const &a1y = pos1[ia].y;
// cvm::real const &a1z = pos1[ia].z;
deriv.calc_derivative_wrt_group2(ia, &dl0_2, &dq0_2, &ds_2);
// make an infitesimal move along each cartesian coordinate of
// this atom, and solve again the eigenvector problem
for (size_t comp = 0; comp < 3; comp++) {
std::memcpy(S_new, rot.S_backup, sizeof(cvm::real) * 4 * 4);
std::memset(S_new_eigval, 0, sizeof(cvm::real) * 4);
std::memset(S_new_eigvec, 0, sizeof(cvm::real) * 4 * 4);
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
S_new[i][j] +=
colvarmodule::debug_gradients_step_size * ds_2[i][j][comp];
}
}
#ifdef COLVARS_LAMMPS
ecalc->Diagonalize(S_new, S_new_eigval, S_new_eigvec);
#else
NR::diagonalize_matrix(S_new, S_new_eigval, S_new_eigvec);
#endif
cvm::real const &L0_new = S_new_eigval[0];
cvm::quaternion const Q0_new(S_new_eigvec[0]);
cvm::real const DL0 = (dl0_2[comp]) * colvarmodule::debug_gradients_step_size;
cvm::quaternion const DQ0(dq0_2[0][comp] * colvarmodule::debug_gradients_step_size,
dq0_2[1][comp] * colvarmodule::debug_gradients_step_size,
dq0_2[2][comp] * colvarmodule::debug_gradients_step_size,
dq0_2[3][comp] * colvarmodule::debug_gradients_step_size);
cvm::log( "|(l_0+dl_0) - l_0^new|/l_0 = "+
cvm::to_str(cvm::fabs(L0+DL0 - L0_new)/L0, cvm::cv_width, cvm::cv_prec)+
", |(q_0+dq_0) - q_0^new| = "+
cvm::to_str((Q0+DQ0 - Q0_new).norm(), cvm::cv_width, cvm::cv_prec)+
"\n");
}
}
}
#endif // COLVAR_ROTATION_DERIVATIVE

View File

@ -13,10 +13,12 @@
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include "colvardeps.h"
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvarparse.h" #include "colvarparse.h"
#include "colvaratoms.h" #include "colvaratoms.h"
#include "colvar_rotation_derivative.h"
cvm::atom::atom() cvm::atom::atom()
@ -118,6 +120,11 @@ cvm::atom_group::~atom_group()
fitting_group = NULL; fitting_group = NULL;
} }
if (rot_deriv != nullptr) {
delete rot_deriv;
rot_deriv = nullptr;
}
cvm::main()->unregister_named_atom_group(this); cvm::main()->unregister_named_atom_group(this);
} }
@ -226,6 +233,7 @@ int cvm::atom_group::init()
b_dummy = false; b_dummy = false;
b_user_defined_fit = false; b_user_defined_fit = false;
fitting_group = NULL; fitting_group = NULL;
rot_deriv = nullptr;
noforce = false; noforce = false;
@ -278,7 +286,7 @@ int cvm::atom_group::init_dependencies() {
// Initialize feature_states for each instance // Initialize feature_states for each instance
// default as unavailable, not enabled // default as unavailable, not enabled
feature_states.reserve(f_ag_ntot); feature_states.reserve(f_ag_ntot);
for (i = 0; i < colvardeps::f_ag_ntot; i++) { for (i = feature_states.size(); i < colvardeps::f_ag_ntot; i++) {
feature_states.push_back(feature_state(false, false)); feature_states.push_back(feature_state(false, false));
} }
@ -317,6 +325,13 @@ int cvm::atom_group::setup()
return COLVARS_OK; return COLVARS_OK;
} }
void cvm::atom_group::setup_rotation_derivative() {
if (rot_deriv != nullptr) delete rot_deriv;
rot_deriv = new rotation_derivative<cvm::atom, cvm::atom_pos>(
rot, fitting_group ? fitting_group->atoms : this->atoms, ref_pos
);
}
void cvm::atom_group::update_total_mass() void cvm::atom_group::update_total_mass()
{ {
@ -383,7 +398,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
// } // }
// colvarparse::Parse_Mode mode = parse_normal; // colvarparse::Parse_Mode mode = parse_normal;
int parse_error = COLVARS_OK; int error_code = COLVARS_OK;
// Optional group name will let other groups reuse atom definition // Optional group name will let other groups reuse atom definition
if (get_keyval(group_conf, "name", name)) { if (get_keyval(group_conf, "name", name)) {
@ -433,7 +448,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::error("Error: cannot find atom group with name " + atoms_of + ".\n"); cvm::error("Error: cannot find atom group with name " + atoms_of + ".\n");
return COLVARS_ERROR; return COLVARS_ERROR;
} }
parse_error |= add_atoms_of_group(ag); error_code |= add_atoms_of_group(ag);
} }
} }
@ -447,7 +462,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
std::string numbers_conf = ""; std::string numbers_conf = "";
size_t pos = 0; size_t pos = 0;
while (key_lookup(group_conf, "atomNumbers", &numbers_conf, &pos)) { while (key_lookup(group_conf, "atomNumbers", &numbers_conf, &pos)) {
parse_error |= add_atom_numbers(numbers_conf); error_code |= add_atom_numbers(numbers_conf);
numbers_conf = ""; numbers_conf = "";
} }
} }
@ -456,7 +471,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
std::string index_group_name; std::string index_group_name;
if (get_keyval(group_conf, "indexGroup", index_group_name)) { if (get_keyval(group_conf, "indexGroup", index_group_name)) {
// use an index group from the index file read globally // use an index group from the index file read globally
parse_error |= add_index_group(index_group_name); error_code |= add_index_group(index_group_name);
} }
} }
@ -465,7 +480,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
size_t pos = 0; size_t pos = 0;
while (key_lookup(group_conf, "atomNumbersRange", while (key_lookup(group_conf, "atomNumbersRange",
&range_conf, &pos)) { &range_conf, &pos)) {
parse_error |= add_atom_numbers_range(range_conf); error_code |= add_atom_numbers_range(range_conf);
range_conf = ""; range_conf = "";
} }
} }
@ -492,7 +507,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::error("Error: more instances of \"atomNameResidueRange\" than " cvm::error("Error: more instances of \"atomNameResidueRange\" than "
"values of \"psfSegID\".\n", COLVARS_INPUT_ERROR); "values of \"psfSegID\".\n", COLVARS_INPUT_ERROR);
} else { } else {
parse_error |= add_atom_name_residue_range(psf_segids.size() ? error_code |= add_atom_name_residue_range(psf_segids.size() ?
*psii : std::string(""), range_conf); *psii : std::string(""), range_conf);
if (psf_segids.size()) psii++; if (psf_segids.size()) psii++;
} }
@ -517,26 +532,26 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", COLVARS_INPUT_ERROR); cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", COLVARS_INPUT_ERROR);
} }
// NOTE: calls to add_atom() and/or add_atom_id() are in the proxy-implemented function error_code |= cvm::main()->proxy->load_atoms_pdb(atoms_file_name.c_str(), *this, atoms_col,
parse_error |= cvm::load_atoms(atoms_file_name.c_str(), *this, atoms_col, atoms_col_value); atoms_col_value);
} }
} }
// Catch any errors from all the initialization steps above // Catch any errors from all the initialization steps above
if (parse_error || cvm::get_error()) return (parse_error || cvm::get_error()); if (error_code || cvm::get_error()) return (error_code || cvm::get_error());
// checks of doubly-counted atoms have been handled by add_atom() already // checks of doubly-counted atoms have been handled by add_atom() already
if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos())) { if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos())) {
parse_error |= set_dummy(); error_code |= set_dummy();
parse_error |= set_dummy_pos(dummy_atom_pos); error_code |= set_dummy_pos(dummy_atom_pos);
} else { } else {
if (!(atoms_ids.size())) { if (!(atoms_ids.size())) {
parse_error |= cvm::error("Error: no atoms defined for atom group \""+ error_code |= cvm::error("Error: no atoms defined for atom group \"" + key + "\".\n",
key+"\".\n", COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
// whether these atoms will ever receive forces or not // whether these atoms will ever receive forces or not
@ -546,7 +561,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
} }
// Now that atoms are defined we can parse the detailed fitting options // Now that atoms are defined we can parse the detailed fitting options
parse_error |= parse_fitting_options(group_conf); error_code |= parse_fitting_options(group_conf);
if (is_enabled(f_ag_scalable) && !b_dummy) { if (is_enabled(f_ag_scalable) && !b_dummy) {
cvm::log("Enabling scalable calculation for group \""+this->key+"\".\n"); cvm::log("Enabling scalable calculation for group \""+this->key+"\".\n");
@ -583,7 +598,9 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::log(print_atom_ids()); cvm::log(print_atom_ids());
} }
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); if (is_enabled(f_ag_rotate)) setup_rotation_derivative();
return error_code;
} }
@ -883,8 +900,6 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf)
"to its radius of gyration), the optimal rotation and its gradients may become discontinuous. " "to its radius of gyration), the optimal rotation and its gradients may become discontinuous. "
"If that happens, use fittingGroup (or a different definition for it if already defined) " "If that happens, use fittingGroup (or a different definition for it if already defined) "
"to align the coordinates.\n"); "to align the coordinates.\n");
// initialize rot member data
rot.request_group1_gradients(group_for_fit->size());
} }
} }
@ -912,7 +927,6 @@ void cvm::atom_group::do_feature_side_effects(int id)
if (is_enabled(f_ag_center) || is_enabled(f_ag_rotate)) { if (is_enabled(f_ag_center) || is_enabled(f_ag_rotate)) {
atom_group *group_for_fit = fitting_group ? fitting_group : this; atom_group *group_for_fit = fitting_group ? fitting_group : this;
group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0)); group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0));
rot.request_group1_gradients(group_for_fit->size());
} }
break; break;
} }
@ -1045,17 +1059,18 @@ void cvm::atom_group::calc_apply_roto_translation()
// rotate the group (around the center of geometry if f_ag_center is // rotate the group (around the center of geometry if f_ag_center is
// enabled, around the origin otherwise) // enabled, around the origin otherwise)
rot.calc_optimal_rotation(fitting_group ? rot.calc_optimal_rotation(fitting_group ?
fitting_group->positions() : fitting_group->atoms:
this->positions(), this->atoms,
ref_pos); ref_pos);
const auto rot_mat = rot.matrix();
cvm::atom_iter ai; cvm::atom_iter ai;
for (ai = this->begin(); ai != this->end(); ai++) { for (ai = this->begin(); ai != this->end(); ai++) {
ai->pos = rot.rotate(ai->pos); ai->pos = rot_mat * ai->pos;
} }
if (fitting_group) { if (fitting_group) {
for (ai = fitting_group->begin(); ai != fitting_group->end(); ai++) { for (ai = fitting_group->begin(); ai != fitting_group->end(); ai++) {
ai->pos = rot.rotate(ai->pos); ai->pos = rot_mat * ai->pos;
} }
} }
} }
@ -1095,9 +1110,10 @@ void cvm::atom_group::read_velocities()
if (is_enabled(f_ag_rotate)) { if (is_enabled(f_ag_rotate)) {
const auto rot_mat = rot.matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_velocity(); ai->read_velocity();
ai->vel = rot.rotate(ai->vel); ai->vel = rot_mat * ai->vel;
} }
} else { } else {
@ -1116,9 +1132,10 @@ void cvm::atom_group::read_total_forces()
if (is_enabled(f_ag_rotate)) { if (is_enabled(f_ag_rotate)) {
const auto rot_mat = rot.matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_total_force(); ai->read_total_force();
ai->total_force = rot.rotate(ai->total_force); ai->total_force = rot_mat * ai->total_force;
} }
} else { } else {
@ -1200,52 +1217,71 @@ void cvm::atom_group::calc_fit_gradients()
if (cvm::debug()) if (cvm::debug())
cvm::log("Calculating fit gradients.\n"); cvm::log("Calculating fit gradients.\n");
cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this; if (is_enabled(f_ag_center) && is_enabled(f_ag_rotate))
calc_fit_gradients_impl<true, true>();
if (is_enabled(f_ag_center)) { if (is_enabled(f_ag_center) && !is_enabled(f_ag_rotate))
// add the center of geometry contribution to the gradients calc_fit_gradients_impl<true, false>();
cvm::rvector atom_grad; if (!is_enabled(f_ag_center) && is_enabled(f_ag_rotate))
calc_fit_gradients_impl<false, true>();
for (size_t i = 0; i < this->size(); i++) { if (!is_enabled(f_ag_center) && !is_enabled(f_ag_rotate))
atom_grad += atoms[i].grad; calc_fit_gradients_impl<false, false>();
}
if (is_enabled(f_ag_rotate)) atom_grad = (rot.inverse()).rotate(atom_grad);
atom_grad *= (-1.0)/(cvm::real(group_for_fit->size()));
for (size_t j = 0; j < group_for_fit->size(); j++) {
group_for_fit->fit_gradients[j] = atom_grad;
}
}
if (is_enabled(f_ag_rotate)) {
// add the rotation matrix contribution to the gradients
cvm::rotation const rot_inv = rot.inverse();
for (size_t i = 0; i < this->size(); i++) {
// compute centered, unrotated position
cvm::atom_pos const pos_orig =
rot_inv.rotate((is_enabled(f_ag_center) ? (atoms[i].pos - ref_pos_cog) : (atoms[i].pos)));
// calculate \partial(R(q) \vec{x}_i)/\partial q) \cdot \partial\xi/\partial\vec{x}_i
cvm::quaternion const dxdq =
rot.q.position_derivative_inner(pos_orig, atoms[i].grad);
for (size_t j = 0; j < group_for_fit->size(); j++) {
// multiply by {\partial q}/\partial\vec{x}_j and add it to the fit gradients
for (size_t iq = 0; iq < 4; iq++) {
group_for_fit->fit_gradients[j] += dxdq[iq] * rot.dQ0_1[j][iq];
}
}
}
}
if (cvm::debug()) if (cvm::debug())
cvm::log("Done calculating fit gradients.\n"); cvm::log("Done calculating fit gradients.\n");
} }
template <bool B_ag_center, bool B_ag_rotate>
void cvm::atom_group::calc_fit_gradients_impl() {
cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this;
// the center of geometry contribution to the gradients
cvm::rvector atom_grad;
// the rotation matrix contribution to the gradients
const auto rot_inv = rot.inverse().matrix();
// temporary variables for computing and summing derivatives
cvm::real sum_dxdq[4] = {0, 0, 0, 0};
cvm::vector1d<cvm::rvector> dq0_1(4);
// loop 1: iterate over the current atom group
for (size_t i = 0; i < size(); i++) {
cvm::atom_pos pos_orig;
if (B_ag_center) {
atom_grad += atoms[i].grad;
if (B_ag_rotate) pos_orig = rot_inv * (atoms[i].pos - ref_pos_cog);
} else {
if (B_ag_rotate) pos_orig = atoms[i].pos;
}
if (B_ag_rotate) {
// calculate \partial(R(q) \vec{x}_i)/\partial q) \cdot \partial\xi/\partial\vec{x}_i
cvm::quaternion const dxdq =
rot.q.position_derivative_inner(pos_orig, atoms[i].grad);
sum_dxdq[0] += dxdq[0];
sum_dxdq[1] += dxdq[1];
sum_dxdq[2] += dxdq[2];
sum_dxdq[3] += dxdq[3];
}
}
if (B_ag_center) {
if (B_ag_rotate) atom_grad = rot.inverse().matrix() * atom_grad;
atom_grad *= (-1.0)/(cvm::real(group_for_fit->size()));
}
// loop 2: iterate over the fitting group
if (B_ag_rotate) rot_deriv->prepare_derivative(rotation_derivative_dldq::use_dq);
for (size_t j = 0; j < group_for_fit->size(); j++) {
if (B_ag_center) {
group_for_fit->fit_gradients[j] = atom_grad;
}
if (B_ag_rotate) {
rot_deriv->calc_derivative_wrt_group1(j, nullptr, &dq0_1);
// multiply by {\partial q}/\partial\vec{x}_j and add it to the fit gradients
group_for_fit->fit_gradients[j] += sum_dxdq[0] * dq0_1[0] +
sum_dxdq[1] * dq0_1[1] +
sum_dxdq[2] * dq0_1[2] +
sum_dxdq[3] * dq0_1[3];
}
}
}
std::vector<cvm::atom_pos> cvm::atom_group::positions() const std::vector<cvm::atom_pos> cvm::atom_group::positions() const
{ {
if (b_dummy) { if (b_dummy) {
@ -1373,9 +1409,9 @@ void cvm::atom_group::apply_colvar_force(cvm::real const &force)
if (is_enabled(f_ag_rotate)) { if (is_enabled(f_ag_rotate)) {
// rotate forces back to the original frame // rotate forces back to the original frame
cvm::rotation const rot_inv = rot.inverse(); const auto rot_inv = rot.inverse().matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(rot_inv.rotate(force * ai->grad)); ai->apply_force(rot_inv * (force * ai->grad));
} }
} else { } else {
@ -1418,9 +1454,9 @@ void cvm::atom_group::apply_force(cvm::rvector const &force)
if (is_enabled(f_ag_rotate)) { if (is_enabled(f_ag_rotate)) {
cvm::rotation const rot_inv = rot.inverse(); const auto rot_inv = rot.inverse().matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(rot_inv.rotate((ai->mass/total_mass) * force)); ai->apply_force(rot_inv * ((ai->mass/total_mass) * force));
} }
} else { } else {

View File

@ -15,6 +15,9 @@
#include "colvarparse.h" #include "colvarparse.h"
#include "colvardeps.h" #include "colvardeps.h"
template <typename T1, typename T2>
struct rotation_derivative;
/// \brief Stores numeric id, mass and all mutable data for an atom, /// \brief Stores numeric id, mass and all mutable data for an atom,
/// mostly used by a \link colvar::cvc \endlink /// mostly used by a \link colvar::cvc \endlink
@ -167,7 +170,7 @@ public:
atom_group(std::vector<cvm::atom> const &atoms_in); atom_group(std::vector<cvm::atom> const &atoms_in);
/// \brief Destructor /// \brief Destructor
~atom_group(); ~atom_group() override;
/// \brief Optional name to reuse properties of this in other groups /// \brief Optional name to reuse properties of this in other groups
std::string name; std::string name;
@ -180,7 +183,7 @@ public:
int init(); int init();
/// \brief Initialize dependency tree /// \brief Initialize dependency tree
virtual int init_dependencies(); int init_dependencies() override;
/// \brief Update data required to calculate cvc's /// \brief Update data required to calculate cvc's
int setup(); int setup();
@ -221,16 +224,13 @@ public:
static std::vector<feature *> ag_features; static std::vector<feature *> ag_features;
/// \brief Implementation of the feature list accessor for atom group /// \brief Implementation of the feature list accessor for atom group
virtual const std::vector<feature *> &features() const const std::vector<feature *> &features() const override { return ag_features; }
std::vector<feature *> &modify_features() override { return ag_features; }
static void delete_features()
{ {
return ag_features; for (size_t i = 0; i < ag_features.size(); i++) {
}
virtual std::vector<feature *> &modify_features()
{
return ag_features;
}
static void delete_features() {
for (size_t i=0; i < ag_features.size(); i++) {
delete ag_features[i]; delete ag_features[i];
} }
ag_features.clear(); ag_features.clear();
@ -330,6 +330,9 @@ public:
/// The rotation calculated automatically if f_ag_rotate is defined /// The rotation calculated automatically if f_ag_rotate is defined
cvm::rotation rot; cvm::rotation rot;
/// Rotation derivative;
rotation_derivative<cvm::atom, cvm::atom_pos>* rot_deriv;
/// \brief Indicates that the user has explicitly set centerToReference or /// \brief Indicates that the user has explicitly set centerToReference or
/// rotateReference, and the corresponding reference: /// rotateReference, and the corresponding reference:
/// cvc's (eg rmsd, eigenvector) will not override the user's choice /// cvc's (eg rmsd, eigenvector) will not override the user's choice
@ -369,6 +372,8 @@ public:
/// \brief (Re)calculate the optimal roto-translation /// \brief (Re)calculate the optimal roto-translation
void calc_apply_roto_translation(); void calc_apply_roto_translation();
void setup_rotation_derivative();
/// \brief Save aside the center of geometry of the reference positions, /// \brief Save aside the center of geometry of the reference positions,
/// then subtract it from them /// then subtract it from them
/// ///
@ -492,6 +497,16 @@ public:
/// \brief Calculate the derivatives of the fitting transformation /// \brief Calculate the derivatives of the fitting transformation
void calc_fit_gradients(); void calc_fit_gradients();
/*! @brief Actual implementation of `calc_fit_gradients`. The template is
* used to avoid branching inside the loops in case that the CPU
* branch prediction is broken (or further migration to GPU code).
* @tparam B_ag_center Centered the reference to origin? This should follow
* the value of `is_enabled(f_ag_center)`.
* @tparam B_ag_rotate Calculate the optimal rotation? This should follow
* the value of `is_enabled(f_ag_rotate)`.
*/
template <bool B_ag_center, bool B_ag_rotate> void calc_fit_gradients_impl();
/// \brief Derivatives of the fitting transformation /// \brief Derivatives of the fitting transformation
std::vector<cvm::atom_pos> fit_gradients; std::vector<cvm::atom_pos> fit_gradients;
@ -525,7 +540,7 @@ public:
/// Implements possible actions to be carried out /// Implements possible actions to be carried out
/// when a given feature is enabled /// when a given feature is enabled
/// This overloads the base function in colvardeps /// This overloads the base function in colvardeps
void do_feature_side_effects(int id); void do_feature_side_effects(int id) override;
}; };

View File

@ -15,6 +15,7 @@
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarbias.h" #include "colvarbias.h"
#include "colvargrid.h" #include "colvargrid.h"
#include "colvars_memstream.h"
colvarbias::colvarbias(char const *key) colvarbias::colvarbias(char const *key)
@ -166,6 +167,10 @@ int colvarbias::init_dependencies() {
init_feature(f_cvb_get_total_force, "obtain_total_force", f_type_dynamic); init_feature(f_cvb_get_total_force, "obtain_total_force", f_type_dynamic);
require_feature_children(f_cvb_get_total_force, f_cv_total_force); require_feature_children(f_cvb_get_total_force, f_cv_total_force);
// Depending on back-end, we may not obtain total force at step 0
if (!cvm::main()->proxy->total_forces_same_step()) {
exclude_feature_self(f_cvb_get_total_force, f_cvb_step_zero_data);
}
init_feature(f_cvb_output_acc_work, "output_accumulated_work", f_type_user); init_feature(f_cvb_output_acc_work, "output_accumulated_work", f_type_user);
require_feature_self(f_cvb_output_acc_work, f_cvb_apply_force); require_feature_self(f_cvb_output_acc_work, f_cvb_apply_force);
@ -192,6 +197,8 @@ int colvarbias::init_dependencies() {
init_feature(f_cvb_scale_biasing_force, "scale_biasing_force", f_type_user); init_feature(f_cvb_scale_biasing_force, "scale_biasing_force", f_type_user);
require_feature_children(f_cvb_scale_biasing_force, f_cv_grid); require_feature_children(f_cvb_scale_biasing_force, f_cv_grid);
init_feature(f_cvb_extended, "Bias on extended-Lagrangian variables", f_type_static);
// check that everything is initialized // check that everything is initialized
for (i = 0; i < colvardeps::f_cvb_ntot; i++) { for (i = 0; i < colvardeps::f_cvb_ntot; i++) {
if (is_not_set(i)) { if (is_not_set(i)) {
@ -202,7 +209,7 @@ int colvarbias::init_dependencies() {
// Initialize feature_states for each instance // Initialize feature_states for each instance
feature_states.reserve(f_cvb_ntot); feature_states.reserve(f_cvb_ntot);
for (i = 0; i < f_cvb_ntot; i++) { for (i = feature_states.size(); i < f_cvb_ntot; i++) {
feature_states.push_back(feature_state(true, false)); feature_states.push_back(feature_state(true, false));
// Most features are available, so we set them so // Most features are available, so we set them so
// and list exceptions below // and list exceptions below
@ -436,43 +443,55 @@ int colvarbias::bin_num()
cvm::error("Error: bin_num() not implemented.\n"); cvm::error("Error: bin_num() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
} }
int colvarbias::current_bin() int colvarbias::current_bin()
{ {
cvm::error("Error: current_bin() not implemented.\n"); cvm::error("Error: current_bin() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
} }
int colvarbias::bin_count(int /* bin_index */) int colvarbias::bin_count(int /* bin_index */)
{ {
cvm::error("Error: bin_count() not implemented.\n"); cvm::error("Error: bin_count() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
} }
int colvarbias::local_sample_count(int /* radius */)
{
cvm::error("Error: local_sample_count() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
int colvarbias::replica_share() int colvarbias::replica_share()
{ {
cvm::error("Error: replica_share() not implemented.\n"); cvm::error("Error: replica_share() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
} }
size_t colvarbias::replica_share_freq() const
{
return 0;
}
std::string const colvarbias::get_state_params() const std::string const colvarbias::get_state_params() const
{ {
std::ostringstream os; std::ostringstream os;
os << "step " << cvm::step_absolute() << "\n" os << " step " << cvm::step_absolute() << "\n"
<< "name " << this->name << "\n"; << " name " << this->name << "\n";
return os.str(); return os.str();
} }
int colvarbias::set_state_params(std::string const &conf) int colvarbias::check_matching_state(std::string const &conf)
{ {
matching_state = false;
std::string check_name = ""; std::string check_name = "";
colvarparse::get_keyval(conf, "name", check_name, colvarparse::get_keyval(conf, "name", check_name,
std::string(""), colvarparse::parse_silent); std::string(""), colvarparse::parse_silent);
if (check_name.size() == 0) { if (check_name.size() == 0) {
cvm::error("Error: \""+bias_type+"\" block within the restart file " return cvm::error("Error: \""+bias_type+"\" block within the state file "
"has no identifiers.\n", COLVARS_INPUT_ERROR); "has no identifiers.\n", COLVARS_INPUT_ERROR);
} }
if (check_name != this->name) { if (check_name != this->name) {
@ -480,11 +499,17 @@ int colvarbias::set_state_params(std::string const &conf)
cvm::log("Ignoring state of bias \""+check_name+ cvm::log("Ignoring state of bias \""+check_name+
"\": this bias is named \""+name+"\".\n"); "\": this bias is named \""+name+"\".\n");
} }
return COLVARS_OK; matching_state = false;
} else {
matching_state = true;
} }
matching_state = true; return COLVARS_OK;
}
int colvarbias::set_state_params(std::string const &conf)
{
colvarparse::get_keyval(conf, "step", state_file_step, colvarparse::get_keyval(conf, "step", state_file_step,
cvm::step_absolute(), colvarparse::parse_silent); cvm::step_absolute(), colvarparse::parse_silent);
@ -495,76 +520,119 @@ int colvarbias::set_state_params(std::string const &conf)
std::ostream & colvarbias::write_state(std::ostream &os) std::ostream & colvarbias::write_state(std::ostream &os)
{ {
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Writing state file for bias \""+name+"\"\n"); cvm::log("Writing formatted state for bias \""+name+"\"\n");
} }
os.setf(std::ios::scientific, std::ios::floatfield); os.setf(std::ios::scientific, std::ios::floatfield);
os.precision(cvm::cv_prec); os.precision(cvm::cv_prec);
os << state_keyword << " {\n" os << state_keyword << " {\n"
<< " configuration {\n"; << " configuration {\n"
std::istringstream is(get_state_params()); << get_state_params()
std::string line; << " }\n";
while (std::getline(is, line)) {
os << " " << line << "\n";
}
os << " }\n";
write_state_data(os); write_state_data(os);
os << "}\n\n"; os << "}\n\n";
return os; return os;
} }
std::istream & colvarbias::read_state(std::istream &is) cvm::memory_stream & colvarbias::write_state(cvm::memory_stream &os)
{ {
std::streampos const start_pos = is.tellg(); if (cvm::debug()) {
cvm::log("Writing unformatted state for bias \""+name+"\"\n");
}
os << state_keyword << std::string("configuration") << get_state_params();
write_state_data(os);
return os;
}
template <typename IST, typename SPT>
void raise_error_rewind(IST &is, SPT start_pos, std::string const &bias_type,
std::string const &bias_name, std::string const added_msg = "")
{
auto state = is.rdstate();
is.clear();
is.seekg(start_pos);
is.setstate(state | std::ios::failbit);
cvm::error("Error: in reading state for \"" + bias_type + "\" bias \"" + bias_name +
"\" at position " + cvm::to_str(static_cast<size_t>(is.tellg())) + " in stream." +
added_msg + "\n",
COLVARS_INPUT_ERROR);
}
template <typename IST> IST & colvarbias::read_state_template_(IST &is)
{
auto const start_pos = is.tellg();
std::string key, brace, conf; std::string key, brace, conf;
if ( !(is >> key) || !(key == state_keyword || key == bias_type) || if (is >> key) {
!(is >> brace) || !(brace == "{") || if (key == state_keyword || key == bias_type) {
!(is >> colvarparse::read_block("configuration", &conf)) ||
(set_state_params(conf) != COLVARS_OK) ) { if (! std::is_same<IST, cvm::memory_stream>::value) {
cvm::error("Error: in reading state configuration for \""+bias_type+ // Formatted input only
"\" bias \""+ if (!(is >> brace) || !(brace == "{") ) {
this->name+"\" at position "+ raise_error_rewind(is, start_pos, bias_type, name);
cvm::to_str(static_cast<size_t>(is.tellg()))+ return is;
" in stream.\n", COLVARS_INPUT_ERROR); }
is.clear(); }
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit); if (!(is >> colvarparse::read_block("configuration", &conf)) ||
(check_matching_state(conf) != COLVARS_OK)) {
raise_error_rewind(is, start_pos, bias_type, name);
return is;
}
} else {
// Not a match for this bias type, rewind without error
is.seekg(start_pos);
return is;
}
} else {
raise_error_rewind(is, start_pos, bias_type, name);
return is; return is;
} }
if (matching_state == false) { if (!matching_state) {
// This state is not for this bias // No errors, but not a match for this bias instance; rewind
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos);
return is; return is;
} }
cvm::log("Restarting "+bias_type+" bias \""+name+"\" from step number "+ if ((set_state_params(conf) != COLVARS_OK) || !read_state_data(is)) {
cvm::to_str(state_file_step)+".\n"); raise_error_rewind(is, start_pos, bias_type, name);
if (!read_state_data(is)) {
cvm::error("Error: in reading state data for \""+bias_type+"\" bias \""+
this->name+"\" at position "+
cvm::to_str(static_cast<size_t>(is.tellg()))+
" in stream.\n", COLVARS_INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
} }
is >> brace; if (! std::is_same<IST, cvm::memory_stream>::value) {
if (brace != "}") { is >> brace;
cvm::error("Error: corrupt restart information for \""+bias_type+"\" bias \""+ if (brace != "}") {
this->name+"\": no matching brace at position "+ cvm::error("Error: corrupt restart information for \""+bias_type+"\" bias \""+
cvm::to_str(static_cast<size_t>(is.tellg()))+ this->name+"\": no matching brace at position "+
" in stream.\n"); cvm::to_str(static_cast<size_t>(is.tellg()))+
is.setstate(std::ios::failbit); " in stream.\n");
raise_error_rewind(is, start_pos, bias_type, name);
}
} }
cvm::log("Restarted " + bias_type + " bias \"" + name + "\" with step number " +
cvm::to_str(state_file_step) + ".\n");
return is; return is;
} }
std::istream &colvarbias::read_state(std::istream &is)
{
return read_state_template_<std::istream>(is);
}
cvm::memory_stream &colvarbias::read_state(cvm::memory_stream &is)
{
return read_state_template_<cvm::memory_stream>(is);
}
int colvarbias::write_state_prefix(std::string const &prefix) int colvarbias::write_state_prefix(std::string const &prefix)
{ {
std::string const filename = std::string const filename =
@ -635,25 +703,51 @@ int colvarbias::read_state_string(char const *buffer)
} }
std::istream & colvarbias::read_state_data_key(std::istream &is, char const *key) std::ostream &colvarbias::write_state_data_key(std::ostream &os, std::string const &key,
bool header)
{ {
std::streampos const start_pos = is.tellg(); os << (header ? "\n" : "") << key << (header ? "\n" : " ");
return os;
}
cvm::memory_stream &colvarbias::write_state_data_key(cvm::memory_stream &os, std::string const &key,
bool /* header */)
{
os << std::string(key);
return os;
}
template <typename IST>
IST &colvarbias::read_state_data_key_template_(IST &is, std::string const &key)
{
auto const start_pos = is.tellg();
std::string key_in; std::string key_in;
if ( !(is >> key_in) || if (is >> key_in) {
!(to_lower_cppstr(key_in) == to_lower_cppstr(std::string(key))) ) { if (key_in != key) {
cvm::error("Error: in reading restart configuration for "+ raise_error_rewind(is, start_pos, bias_type, name,
bias_type+" bias \""+this->name+"\" at position "+ " Expected keyword \"" + std::string(key) + "\", found \"" + key_in +
cvm::to_str(static_cast<size_t>(is.tellg()))+ "\".");
" in stream.\n", COLVARS_INPUT_ERROR); }
is.clear(); } else {
is.seekg(start_pos, std::ios::beg); raise_error_rewind(is, start_pos, bias_type, name);
is.setstate(std::ios::failbit);
return is;
} }
return is; return is;
} }
std::istream & colvarbias::read_state_data_key(std::istream &is, std::string const &key)
{
return read_state_data_key_template_<std::istream>(is, key);
}
cvm::memory_stream & colvarbias::read_state_data_key(cvm::memory_stream &is, std::string const &key)
{
return read_state_data_key_template_<cvm::memory_stream>(is, key);
}
std::ostream & colvarbias::write_traj_label(std::ostream &os) std::ostream & colvarbias::write_traj_label(std::ostream &os)
{ {
@ -686,28 +780,11 @@ colvarbias_ti::colvarbias_ti(char const *key)
// Samples at step zero can not be collected // Samples at step zero can not be collected
feature_states[f_cvb_step_zero_data].available = false; feature_states[f_cvb_step_zero_data].available = false;
} }
ti_avg_forces = NULL;
ti_count = NULL;
} }
colvarbias_ti::~colvarbias_ti() colvarbias_ti::~colvarbias_ti()
{ {
colvarbias_ti::clear_state_data();
}
int colvarbias_ti::clear_state_data()
{
if (ti_avg_forces != NULL) {
delete ti_avg_forces;
ti_avg_forces = NULL;
}
if (ti_count != NULL) {
delete ti_count;
ti_count = NULL;
}
return COLVARS_OK;
} }
@ -765,7 +842,7 @@ int colvarbias_ti::init(std::string const &conf)
int colvarbias_ti::init_grids() int colvarbias_ti::init_grids()
{ {
if (is_enabled(f_cvb_calc_ti_samples)) { if (is_enabled(f_cvb_calc_ti_samples)) {
if (ti_avg_forces == NULL) { if (!ti_avg_forces) {
ti_bin.resize(num_variables()); ti_bin.resize(num_variables());
ti_system_forces.resize(num_variables()); ti_system_forces.resize(num_variables());
for (size_t icv = 0; icv < num_variables(); icv++) { for (size_t icv = 0; icv < num_variables(); icv++) {
@ -773,8 +850,8 @@ int colvarbias_ti::init_grids()
ti_system_forces[icv].is_derivative(); ti_system_forces[icv].is_derivative();
ti_system_forces[icv].reset(); ti_system_forces[icv].reset();
} }
ti_avg_forces = new colvar_grid_gradient(colvars); ti_avg_forces.reset(new colvar_grid_gradient(colvars));
ti_count = new colvar_grid_count(colvars); ti_count.reset(new colvar_grid_count(colvars));
ti_avg_forces->samples = ti_count; ti_avg_forces->samples = ti_count;
ti_count->has_parent_data = true; ti_count->has_parent_data = true;
} }
@ -860,9 +937,22 @@ std::ostream & colvarbias_ti::write_state_data(std::ostream &os)
if (! is_enabled(f_cvb_calc_ti_samples)) { if (! is_enabled(f_cvb_calc_ti_samples)) {
return os; return os;
} }
os << "\nhistogram\n"; write_state_data_key(os, "histogram");
ti_count->write_raw(os); ti_count->write_raw(os);
os << "\nsystem_forces\n"; write_state_data_key(os, "system_forces");
ti_avg_forces->write_raw(os);
return os;
}
cvm::memory_stream & colvarbias_ti::write_state_data(cvm::memory_stream &os)
{
if (! is_enabled(f_cvb_calc_ti_samples)) {
return os;
}
write_state_data_key(os, "histogram");
ti_count->write_raw(os);
write_state_data_key(os, "system_forces");
ti_avg_forces->write_raw(os); ti_avg_forces->write_raw(os);
return os; return os;
} }
@ -895,6 +985,33 @@ std::istream & colvarbias_ti::read_state_data(std::istream &is)
} }
cvm::memory_stream & colvarbias_ti::read_state_data(cvm::memory_stream &is)
{
if (! is_enabled(f_cvb_calc_ti_samples)) {
return is;
}
if (cvm::debug()) {
cvm::log("Reading state data for the TI estimator.\n");
}
if (! read_state_data_key(is, "histogram")) {
return is;
}
if (! ti_count->read_raw(is)) {
return is;
}
if (! read_state_data_key(is, "system_forces")) {
return is;
}
if (! ti_avg_forces->read_raw(is)) {
return is;
}
if (cvm::debug()) {
cvm::log("Done reading state data for the TI estimator.\n");
}
return is;
}
int colvarbias_ti::write_output_files() int colvarbias_ti::write_output_files()
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;

View File

@ -10,6 +10,8 @@
#ifndef COLVARBIAS_H #ifndef COLVARBIAS_H
#define COLVARBIAS_H #define COLVARBIAS_H
#include <memory>
#include "colvar.h" #include "colvar.h"
#include "colvarparse.h" #include "colvarparse.h"
#include "colvardeps.h" #include "colvardeps.h"
@ -91,11 +93,16 @@ public:
// FIXME this is currently 1D only // FIXME this is currently 1D only
virtual int current_bin(); virtual int current_bin();
//// Give the count at a given bin index. //// Give the count at a given bin index.
// FIXME this is currently 1D only
virtual int bin_count(int bin_index); virtual int bin_count(int bin_index);
/// Return the average number of samples in a given "radius" around current bin
virtual int local_sample_count(int radius);
//// Share information between replicas, whatever it may be. //// Share information between replicas, whatever it may be.
virtual int replica_share(); virtual int replica_share();
/// Report the frequency at which this bias needs to communicate with replicas
virtual size_t replica_share_freq() const;
/// Perform analysis tasks /// Perform analysis tasks
virtual void analyze() {} virtual void analyze() {}
@ -133,32 +140,87 @@ public:
/// Write the values of specific mutable properties to a string /// Write the values of specific mutable properties to a string
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
/// Check the name of the bias vs. the given string, set the matching_state flag accordingly
int check_matching_state(std::string const &conf);
/// Read the values of specific mutable properties from a string /// Read the values of specific mutable properties from a string
virtual int set_state_params(std::string const &state_conf); virtual int set_state_params(std::string const &state_conf);
/// Write all mutable data not already written by get_state_params() /// Write all mutable data not already written by get_state_params() to a formatted stream
virtual std::ostream & write_state_data(std::ostream &os) virtual std::ostream & write_state_data(std::ostream &os)
{ {
return os; return os;
} }
/// Read all mutable data not already set by set_state_params() /// Write all mutable data not already written by get_state_params() to an unformatted stream
virtual cvm::memory_stream & write_state_data(cvm::memory_stream &os)
{
return os;
}
/// Read all mutable data not already set by set_state_params() from a formatted stream
virtual std::istream & read_state_data(std::istream &is) virtual std::istream & read_state_data(std::istream &is)
{ {
return is; return is;
} }
/// Read a keyword from the state data (typically a header) /// Read all mutable data not already set by set_state_params() from an unformatted stream
/// \param Input stream virtual cvm::memory_stream & read_state_data(cvm::memory_stream &is)
/// \param Keyword labeling the header block {
std::istream & read_state_data_key(std::istream &is, char const *key); return is;
}
/// Write the bias configuration to a state file or other stream /// Write a keyword header for a data sequence to a formatted stream
std::ostream & write_state(std::ostream &os); /// \param[in,out] os Output stream
/// \param[in] key Keyword labeling the header block
/// \param[in] header Whether this is the header of a multi-line segment vs a single line
std::ostream &write_state_data_key(std::ostream &os, std::string const &key, bool header = true);
/// Read the bias configuration from a restart file or other stream /// Write a keyword header for a data sequence to an unformatted stream
/// \param[in,out] os Output stream
/// \param[in] key Keyword labeling the header block
/// \param[in] header Ignored
cvm::memory_stream &write_state_data_key(cvm::memory_stream &os, std::string const &key,
bool header = true);
private:
/// Read a keyword header for a data sequence from a stream
/// \param[in,out] Input stream
/// \param[in] Keyword labeling the header block; an error will be raised if not matching
template <typename IST> IST &read_state_data_key_template_(IST &is, std::string const &key);
public:
/// Read a keyword header for a data sequence from a formatted stream
/// \param[in,out] Input stream
/// \param[in] Keyword labeling the header block; an error will be raised if not matching
std::istream & read_state_data_key(std::istream &is, std::string const &key);
/// Read a keyword header for a data sequence from an unformatted stream
/// \param[in,out] Input stream
/// \param[in] Keyword labeling the header block; an error will be raised if not matching
cvm::memory_stream & read_state_data_key(cvm::memory_stream &is, std::string const &key);
private:
/// Generic stream reading function (formatted and not)
template <typename IST> IST & read_state_template_(IST &is);
public:
/// Write the bias configuration to a formatted stream
std::ostream &write_state(std::ostream &os);
/// Write the bias configuration to an unformatted stream
cvm::memory_stream & write_state(cvm::memory_stream &os);
/// Read the bias configuration from a formatted stream
std::istream & read_state(std::istream &is); std::istream & read_state(std::istream &is);
/// Read the bias configuration from an unformatted stream
cvm::memory_stream & read_state(cvm::memory_stream &is);
/// Write the bias state to a file with the given prefix /// Write the bias state to a file with the given prefix
int write_state_prefix(std::string const &prefix); int write_state_prefix(std::string const &prefix);
@ -274,8 +336,6 @@ public:
colvarbias_ti(char const *key); colvarbias_ti(char const *key);
virtual ~colvarbias_ti(); virtual ~colvarbias_ti();
virtual int clear_state_data();
virtual int init(std::string const &conf); virtual int init(std::string const &conf);
virtual int init_grids(); virtual int init_grids();
virtual int update(); virtual int update();
@ -288,7 +348,9 @@ public:
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &state_conf); virtual int set_state_params(std::string const &state_conf);
virtual std::ostream & write_state_data(std::ostream &os); virtual std::ostream & write_state_data(std::ostream &os);
virtual cvm::memory_stream & write_state_data(cvm::memory_stream &os);
virtual std::istream & read_state_data(std::istream &is); virtual std::istream & read_state_data(std::istream &is);
virtual cvm::memory_stream & read_state_data(cvm::memory_stream &is);
virtual int write_output_files(); virtual int write_output_files();
protected: protected:
@ -297,10 +359,10 @@ protected:
std::vector<colvarvalue> ti_system_forces; std::vector<colvarvalue> ti_system_forces;
/// Averaged system forces /// Averaged system forces
colvar_grid_gradient *ti_avg_forces; std::shared_ptr<colvar_grid_gradient> ti_avg_forces;
/// Histogram of sampled data /// Histogram of sampled data
colvar_grid_count *ti_count; std::shared_ptr<colvar_grid_count> ti_count;
/// Because total forces may be from the last simulation step, /// Because total forces may be from the last simulation step,
/// store the index of the variables then /// store the index of the variables then

File diff suppressed because it is too large Load Diff

View File

@ -14,13 +14,14 @@
#include <list> #include <list>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <memory>
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvarbias.h" #include "colvarbias.h"
#include "colvargrid.h" #include "colvargrid.h"
#include "colvar_UIestimator.h" #include "colvar_UIestimator.h"
typedef cvm::real* gradient_t; typedef cvm::real *gradient_t;
/// ABF bias /// ABF bias
@ -31,17 +32,14 @@ public:
/// Constructor for ABF bias /// Constructor for ABF bias
colvarbias_abf(char const *key); colvarbias_abf(char const *key);
/// Initializer for ABF bias /// Initializer for ABF bias
virtual int init(std::string const &conf); int init(std::string const &conf) override;
/// Default destructor for ABF bias /// Default destructor for ABF bias
virtual ~colvarbias_abf(); ~colvarbias_abf() override;
/// Per-timestep update of ABF bias /// Per-timestep update of ABF bias
virtual int update(); int update() override;
private: private:
/// Filename prefix for human-readable gradient/sample count output
std::string output_prefix;
/// Base filename(s) for reading previous gradient data (replaces data from restart file) /// Base filename(s) for reading previous gradient data (replaces data from restart file)
std::vector<std::string> input_prefix; std::vector<std::string> input_prefix;
@ -57,8 +55,8 @@ private:
size_t full_samples; size_t full_samples;
/// Number of samples per bin before applying a scaled-down biasing force /// Number of samples per bin before applying a scaled-down biasing force
size_t min_samples; size_t min_samples;
/// Write combined files with a history of all output data? /// Latest absolute time step at which history files were written
bool b_history_files; cvm::step_number history_last_step;
/// Write CZAR output file for stratified eABF (.zgrad) /// Write CZAR output file for stratified eABF (.zgrad)
bool b_czar_window_file; bool b_czar_window_file;
/// Number of timesteps between recording data in history files (if non-zero) /// Number of timesteps between recording data in history files (if non-zero)
@ -99,75 +97,104 @@ private:
gradient_t system_force; gradient_t system_force;
/// n-dim grid of free energy gradients /// n-dim grid of free energy gradients
colvar_grid_gradient *gradients; std::shared_ptr<colvar_grid_gradient> gradients;
/// n-dim grid of number of samples /// n-dim grid of number of samples
colvar_grid_count *samples; std::shared_ptr<colvar_grid_count> samples;
/// n-dim grid of pmf (dimension 1 to 3) /// n-dim grid of pmf (dimension 1 to 3)
integrate_potential *pmf; std::shared_ptr<integrate_potential> pmf;
/// n-dim grid: average force on "real" coordinate for eABF z-based estimator /// n-dim grid: average force on "real" coordinate for eABF z-based estimator
colvar_grid_gradient *z_gradients; std::shared_ptr<colvar_grid_gradient> z_gradients;
/// n-dim grid of number of samples on "real" coordinate for eABF z-based estimator /// n-dim grid of number of samples on "real" coordinate for eABF z-based estimator
colvar_grid_count *z_samples; std::shared_ptr<colvar_grid_count> z_samples;
/// n-dim grid containing CZAR estimator of "real" free energy gradients /// n-dim grid containing CZAR estimatr of "real" free energy gradients
colvar_grid_gradient *czar_gradients; std::shared_ptr<colvar_grid_gradient> czar_gradients;
/// n-dim grid of CZAR pmf (dimension 1 to 3) /// n-dim grid of CZAR pmf (dimension 1 to 3)
integrate_potential *czar_pmf; std::shared_ptr<integrate_potential> czar_pmf;
inline int update_system_force(size_t i) /// Calculate system force for all colvars
{ int update_system_force();
if (colvars[i]->is_enabled(f_cv_subtract_applied_force)) {
// this colvar is already subtracting the ABF force /// Calulate the biasing force for the current bin
system_force[i] = colvars[i]->total_force().real_value; int calc_biasing_force(std::vector<cvm::real> &force);
} else {
system_force[i] = colvars[i]->total_force().real_value /// Calulate the smoothing factor to apply to biasing forces for given local count
- colvar_forces[i].real_value; cvm::real smoothing_factor(cvm::real weight);
// If hideJacobian is active then total_force has an extra term of -fj
// which is the Jacobian-compensating force at the colvar level
}
if (cvm::debug())
cvm::log("ABF System force calc: cv " + cvm::to_str(i) +
" fs " + cvm::to_str(system_force[i]) +
" = ft " + cvm::to_str(colvars[i]->total_force().real_value) +
" - fa " + cvm::to_str(colvar_forces[i].real_value));
return COLVARS_OK;
}
// shared ABF // shared ABF
bool shared_on; bool shared_on;
size_t shared_freq; size_t shared_freq;
cvm::step_number shared_last_step; cvm::step_number shared_last_step;
// Share between replicas -- may be called independently of update
virtual int replica_share();
// Store the last set for shared ABF // Share between replicas -- may be called independently of update
colvar_grid_gradient *last_gradients; int replica_share() override;
colvar_grid_count *last_samples;
// Share data needed for CZAR between replicas - called before output only
int replica_share_CZAR();
/// Report the frequency at which this bias needs to communicate with replicas
size_t replica_share_freq() const override;
// Data just after the last share (start of cycle) in shared ABF
std::unique_ptr<colvar_grid_gradient> last_gradients;
std::shared_ptr<colvar_grid_count> last_samples;
// eABF/CZAR local data last shared
std::unique_ptr<colvar_grid_gradient> z_gradients_in;
std::shared_ptr<colvar_grid_count> z_samples_in;
// ABF data from local replica only in shared ABF
std::shared_ptr<colvar_grid_gradient> local_gradients;
std::shared_ptr<colvar_grid_count> local_samples;
std::unique_ptr<integrate_potential> local_pmf;
// eABF/CZAR data collected from all replicas in shared eABF on replica 0
// if non-shared, aliases of regular CZAR grids, for output purposes
std::shared_ptr<colvar_grid_gradient> global_z_gradients;
std::shared_ptr<colvar_grid_count> global_z_samples;
std::shared_ptr<colvar_grid_gradient> global_czar_gradients;
std::shared_ptr<integrate_potential> global_czar_pmf;
// For Tcl implementation of selection rules. // For Tcl implementation of selection rules.
/// Give the total number of bins for a given bias. /// Give the total number of bins for a given bias.
virtual int bin_num(); int bin_num() override;
/// Calculate the bin index for a given bias. /// Calculate the bin index for a given bias.
virtual int current_bin(); int current_bin() override;
//// Give the count at a given bin index. //// Give the count at a given bin index.
virtual int bin_count(int bin_index); int bin_count(int bin_index) override;
/// Return the average number of samples in a given "radius" around current bin
int local_sample_count(int radius) override;
/// Write human-readable FE gradients and sample count, and DX file in dim > 2 /// Write human-readable FE gradients and sample count, and DX file in dim > 2
void write_gradients_samples(const std::string &prefix, bool close = true); /// \param local write grids contining replica-local data in shared ABF
void write_gradients_samples(const std::string &prefix, bool close = true, bool local = false);
/// Read human-readable FE gradients and sample count (if not using restart) /// Read human-readable FE gradients and sample count (if not using restart)
int read_gradients_samples(); int read_gradients_samples();
/// Template used in write_gradient_samples() /// Shorthand template used in write_gradient_samples()
template <class T> int write_grid_to_file(T const *grid, template <class T> int write_grid_to_file(T const *grid,
std::string const &name, std::string const &name,
bool close); bool close);
virtual std::istream& read_state_data(std::istream&); private:
virtual std::ostream& write_state_data(std::ostream&);
virtual int write_output_files(); /// Generic stream writing function (formatted and not)
template <typename OST> OST &write_state_data_template_(OST &os);
/// Generic stream readingx function (formatted and not)
template <typename IST> IST &read_state_data_template_(IST &is);
public:
std::ostream &write_state_data(std::ostream &os) override;
cvm::memory_stream &write_state_data(cvm::memory_stream &os) override;
std::istream &read_state_data(std::istream &is) override;
cvm::memory_stream &read_state_data(cvm::memory_stream &is) override;
int write_output_files() override;
/// Calculate the bias energy for 1D ABF /// Calculate the bias energy for 1D ABF
virtual int calc_energy(std::vector<colvarvalue> const *values); int calc_energy(std::vector<colvarvalue> const *values) override;
}; };
#endif #endif

View File

@ -0,0 +1,136 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarbias_abmd.h"
#include "colvarproxy.h"
#include <iomanip>
colvarbias_abmd::colvarbias_abmd(char const *key)
: colvarbias(key),
colvarbias_ti(key)
{
}
int colvarbias_abmd::init(std::string const &conf)
{
cvm::main()->cite_feature("ABMD bias");
int err = colvarbias::init(conf);
err |= colvarbias_ti::init(conf);
if (err != COLVARS_OK) return err;
enable(f_cvb_apply_force);
if (num_variables() != 1) {
return cvm::error("ABMD requires exactly one collective variable.\n", COLVARS_INPUT_ERROR);
}
if ( ! (variables(0))->is_enabled(f_cv_scalar) ) {
return cvm::error("ABMD colvar must be scalar.\n", COLVARS_INPUT_ERROR);
}
get_keyval(conf, "forceConstant", k);
get_keyval(conf, "decreasing", decreasing, decreasing);
get_keyval(conf, "stoppingValue", stopping_val);
return COLVARS_OK;
}
int colvarbias_abmd::update()
{
if (!cvm::main()->proxy->simulation_running()) {
return COLVARS_OK;
}
colvar const *cv = variables(0);
cvm::real const val = cv->value().real_value;
if (!ref_initialized) {
ref_val = val;
ref_initialized = true;
}
// Compute sign factor to unify increasing and decreasing cases below
// less conditionals, more arithmetic
cvm::real const sign = decreasing ? -1. : 1.;
cvm::real const diff = (val - ref_val) * sign;
if ( diff > 0. ) {
colvar_forces[0] = 0.;
bias_energy = 0.;
if ( (ref_val-stopping_val) * sign <= 0. ) ref_val = val;
} else {
colvar_forces[0] = - sign * k * diff;
bias_energy = 0.5 * k * diff * diff;;
}
return COLVARS_OK;
}
std::string const colvarbias_abmd::get_state_params() const
{
std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield);
os << " refValue "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< ref_val << "\n";
os << " stoppingValue " << stopping_val << "\n";
os << " forceConstant " << k << "\n";
os << " decreasing " << (decreasing ? "on" : "off") << "\n";
return (colvarbias::get_state_params() + os.str());
}
int colvarbias_abmd::set_state_params(std::string const &conf)
{
int error_code = colvarbias::set_state_params(conf);
if (error_code != COLVARS_OK) {
return error_code;
}
get_keyval(conf, "refValue", ref_val, ref_val,
colvarparse::parse_restart | colvarparse::parse_required);
ref_initialized = true;
get_keyval(conf, "forceConstant", k, k,
colvarparse::parse_restart | colvarparse::parse_required);
get_keyval(conf, "decreasing", decreasing, decreasing,
colvarparse::parse_restart | colvarparse::parse_required);
get_keyval(conf, "stoppingValue", stopping_val, stopping_val,
colvarparse::parse_restart | colvarparse::parse_required);
return COLVARS_OK;
}
std::ostream & colvarbias_abmd::write_traj_label(std::ostream &os)
{
size_t const this_cv_width = (variables(0)->value()).output_width(cvm::cv_width);
os << " ref_"
<< cvm::wrap_string(variables(0)->name, this_cv_width-4);
return os;
}
std::ostream & colvarbias_abmd::write_traj(std::ostream &os)
{
os << " "
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
<< ref_val;
return os;
}

View File

@ -0,0 +1,49 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARBIAS_ABMD_H
#define COLVARBIAS_ABMD_H
#include "colvarbias_restraint.h"
/// \brief Adiabatic Bias MD
class colvarbias_abmd
: public colvarbias_ti
{
public:
colvarbias_abmd(char const *key);
virtual int init(std::string const &conf);
virtual int update();
virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &conf);
virtual std::ostream & write_traj_label(std::ostream &os);
virtual std::ostream & write_traj(std::ostream &os);
protected:
/// \brief Location of the moving wall
cvm::real ref_val = 0.;
/// \brief Has ref_val already been set?
bool ref_initialized = false;
/// \brief Value of the reference where it stops moving
cvm::real stopping_val = 0.;
/// \brief Is the target moving down?
bool decreasing = false;
/// \brief Restraint force constant
cvm::real k = 0.;
};
#endif

View File

@ -9,7 +9,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <cstdlib>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarproxy.h" #include "colvarproxy.h"
@ -40,7 +39,10 @@ colvarbias_alb::colvarbias_alb(char const *key)
int colvarbias_alb::init(std::string const &conf) int colvarbias_alb::init(std::string const &conf)
{ {
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
colvarbias::init(conf); int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
cvm::main()->cite_feature("ALB colvar bias implementation"); cvm::main()->cite_feature("ALB colvar bias implementation");
enable(f_cvb_scalar_variables); enable(f_cvb_scalar_variables);

View File

@ -7,10 +7,13 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <iostream>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvar.h" #include "colvar.h"
#include "colvarbias_histogram.h" #include "colvarbias_histogram.h"
#include "colvars_memstream.h"
colvarbias_histogram::colvarbias_histogram(char const *key) colvarbias_histogram::colvarbias_histogram(char const *key)
@ -23,7 +26,10 @@ colvarbias_histogram::colvarbias_histogram(char const *key)
int colvarbias_histogram::init(std::string const &conf) int colvarbias_histogram::init(std::string const &conf)
{ {
colvarbias::init(conf); int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
cvm::main()->cite_feature("Histogram colvar bias implementation"); cvm::main()->cite_feature("Histogram colvar bias implementation");
enable(f_cvb_scalar_variables); enable(f_cvb_scalar_variables);
@ -125,22 +131,6 @@ int colvarbias_histogram::update()
// assign a valid bin size // assign a valid bin size
bin.assign(num_variables(), 0); bin.assign(num_variables(), 0);
if (out_name.size() == 0) {
// At the first timestep, we need to assign out_name since
// output_prefix is unset during the constructor
if (cvm::step_relative() == 0) {
out_name = cvm::output_prefix() + "." + this->name + ".dat";
cvm::log("Histogram " + this->name + " will be written to file \"" + out_name + "\"\n");
}
}
if (out_name_dx.size() == 0) {
if (cvm::step_relative() == 0) {
out_name_dx = cvm::output_prefix() + "." + this->name + ".dx";
cvm::log("Histogram " + this->name + " will be written to file \"" + out_name_dx + "\"\n");
}
}
if (colvar_array_size == 0) { if (colvar_array_size == 0) {
// update indices for scalar values // update indices for scalar values
size_t i; size_t i;
@ -181,6 +171,16 @@ int colvarbias_histogram::write_output_files()
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
// Set default filenames, if none have been provided
if (!cvm::output_prefix().empty()) {
if (out_name.empty()) {
out_name = cvm::output_prefix() + "." + this->name + ".dat";
}
if (out_name_dx.empty()) {
out_name_dx = cvm::output_prefix() + "." + this->name + ".dx";
}
}
if (out_name.size() && out_name != "none") { if (out_name.size() && out_name != "none") {
cvm::log("Writing the histogram file \""+out_name+"\".\n"); cvm::log("Writing the histogram file \""+out_name+"\".\n");
error_code |= grid->write_multicol(out_name, "histogram output file"); error_code |= grid->write_multicol(out_name, "histogram output file");
@ -197,13 +197,18 @@ int colvarbias_histogram::write_output_files()
std::istream & colvarbias_histogram::read_state_data(std::istream& is) std::istream & colvarbias_histogram::read_state_data(std::istream& is)
{ {
if (! read_state_data_key(is, "grid")) { if (read_state_data_key(is, "grid")) {
return is; grid->read_raw(is);
}
if (! grid->read_raw(is)) {
return is;
} }
return is;
}
cvm::memory_stream & colvarbias_histogram::read_state_data(cvm::memory_stream& is)
{
if (read_state_data_key(is, "grid")) {
grid->read_raw(is);
}
return is; return is;
} }
@ -212,8 +217,16 @@ std::ostream & colvarbias_histogram::write_state_data(std::ostream& os)
{ {
std::ios::fmtflags flags(os.flags()); std::ios::fmtflags flags(os.flags());
os.setf(std::ios::fmtflags(0), std::ios::floatfield); os.setf(std::ios::fmtflags(0), std::ios::floatfield);
os << "grid\n"; write_state_data_key(os, "grid");
grid->write_raw(os, 8); grid->write_raw(os, 8);
os.flags(flags); os.flags(flags);
return os; return os;
} }
cvm::memory_stream & colvarbias_histogram::write_state_data(cvm::memory_stream& os)
{
write_state_data_key(os, "grid");
grid->write_raw(os);
return os;
}

View File

@ -24,11 +24,16 @@ class colvarbias_histogram : public colvarbias {
public: public:
colvarbias_histogram(char const *key); colvarbias_histogram(char const *key);
~colvarbias_histogram(); virtual ~colvarbias_histogram();
virtual int init(std::string const &conf); virtual int init(std::string const &conf);
virtual int update(); virtual int update();
virtual int write_output_files(); virtual int write_output_files();
virtual std::ostream & write_state_data(std::ostream &os);
virtual cvm::memory_stream & write_state_data(cvm::memory_stream &os);
virtual std::istream & read_state_data(std::istream &is);
virtual cvm::memory_stream & read_state_data(cvm::memory_stream &is);
protected: protected:
/// n-dim histogram /// n-dim histogram
@ -40,9 +45,6 @@ protected:
size_t colvar_array_size; size_t colvar_array_size;
/// If colvar_array_size is larger than 1, weigh each one by this number before accumulating the histogram /// If colvar_array_size is larger than 1, weigh each one by this number before accumulating the histogram
std::vector<cvm::real> weights; std::vector<cvm::real> weights;
virtual std::istream & read_state_data(std::istream &is);
virtual std::ostream & write_state_data(std::ostream &os);
}; };
#endif #endif

View File

@ -9,6 +9,7 @@
#include "colvarbias_histogram_reweight_amd.h" #include "colvarbias_histogram_reweight_amd.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvars_memstream.h"
colvarbias_reweightaMD::colvarbias_reweightaMD(char const *key) colvarbias_reweightaMD::colvarbias_reweightaMD(char const *key)
: colvarbias_histogram(key), grid_count(NULL), grid_dV(NULL), : colvarbias_histogram(key), grid_count(NULL), grid_dV(NULL),
@ -343,23 +344,37 @@ void colvarbias_reweightaMD::compute_cumulant_expansion_factor(
} }
} }
std::ostream & colvarbias_reweightaMD::write_state_data(std::ostream& os)
template <typename OST> OST & colvarbias_reweightaMD::write_state_data_template_(OST& os)
{ {
std::ios::fmtflags flags(os.flags()); std::ios::fmtflags flags(os.flags());
os.setf(std::ios::fmtflags(0), std::ios::floatfield); os.setf(std::ios::fmtflags(0), std::ios::floatfield);
os << "grid\n"; write_state_data_key(os, "grid");
grid->write_raw(os, 8); grid->write_raw(os, 8);
os << "grid_count\n"; write_state_data_key(os, "grid_count");
grid_count->write_raw(os, 8); grid_count->write_raw(os, 8);
os << "grid_dV\n"; write_state_data_key(os, "grid_dV");
grid_dV->write_raw(os, 8); grid_dV->write_raw(os, 8);
os << "grid_dV_square\n"; write_state_data_key(os, "grid_dV_square");
grid_dV_square->write_raw(os, 8); grid_dV_square->write_raw(os, 8);
os.flags(flags); os.flags(flags);
return os; return os;
} }
std::istream & colvarbias_reweightaMD::read_state_data(std::istream& is)
std::ostream & colvarbias_reweightaMD::write_state_data(std::ostream& os)
{
return write_state_data_template_<std::ostream>(os);
}
cvm::memory_stream & colvarbias_reweightaMD::write_state_data(cvm::memory_stream& os)
{
return write_state_data_template_<cvm::memory_stream>(os);
}
template <typename IST> IST & colvarbias_reweightaMD::read_state_data_template_(IST& is)
{ {
if (! read_state_data_key(is, "grid")) { if (! read_state_data_key(is, "grid")) {
return is; return is;
@ -387,3 +402,15 @@ std::istream & colvarbias_reweightaMD::read_state_data(std::istream& is)
} }
return is; return is;
} }
std::istream & colvarbias_reweightaMD::read_state_data(std::istream& is)
{
return read_state_data_template_<std::istream>(is);
}
cvm::memory_stream & colvarbias_reweightaMD::read_state_data(cvm::memory_stream& is)
{
return read_state_data_template_<cvm::memory_stream>(is);
}

View File

@ -18,15 +18,9 @@ class colvarbias_reweightaMD : public colvarbias_histogram {
public: public:
colvarbias_reweightaMD(char const *key); colvarbias_reweightaMD(char const *key);
virtual ~colvarbias_reweightaMD(); virtual ~colvarbias_reweightaMD();
#if (__cplusplus >= 201103L)
virtual int init(std::string const &conf) override; virtual int init(std::string const &conf) override;
virtual int update() override; virtual int update() override;
virtual int write_output_files() override; virtual int write_output_files() override;
#else
virtual int init(std::string const &conf);
virtual int update();
virtual int write_output_files();
#endif
/// @brief convert histogram to PMF by taking logarithm and multiplying /// @brief convert histogram to PMF by taking logarithm and multiplying
/// it with -1/beta /// it with -1/beta
@ -85,14 +79,15 @@ protected:
/// Write gradients of the PMF? /// Write gradients of the PMF?
bool b_write_gradients; bool b_write_gradients;
template <typename OST> OST & write_state_data_template_(OST& os);
template <typename IST> IST & read_state_data_template_(IST& is);
/// save and restore /// save and restore
#if (__cplusplus >= 201103L)
virtual std::istream & read_state_data(std::istream &is) override; virtual std::istream & read_state_data(std::istream &is) override;
virtual cvm::memory_stream & read_state_data(cvm::memory_stream &is) override;
virtual std::ostream & write_state_data(std::ostream &os) override; virtual std::ostream & write_state_data(std::ostream &os) override;
#else virtual cvm::memory_stream & write_state_data(cvm::memory_stream &os) override;
virtual std::istream & read_state_data(std::istream &is);
virtual std::ostream & write_state_data(std::ostream &os);
#endif
private: private:
/// temporary grids for evaluating PMFs /// temporary grids for evaluating PMFs
colvar_grid_scalar *pmf_grid_exp_avg; colvar_grid_scalar *pmf_grid_exp_avg;

View File

@ -7,29 +7,33 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <iostream>
#include <sstream>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <algorithm> #include <algorithm>
// used to set the absolute path of a replica file // Define function to get the absolute path of a replica file
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
#include <direct.h> #include <direct.h>
#define CHDIR ::_chdir #define GETCWD(BUF, SIZE) ::_getcwd(BUF, SIZE)
#define GETCWD ::_getcwd
#define PATHSEP "\\" #define PATHSEP "\\"
#else #else
#include <unistd.h> #include <unistd.h>
#define CHDIR ::chdir #define GETCWD(BUF, SIZE) ::getcwd(BUF, SIZE)
#define GETCWD ::getcwd
#define PATHSEP "/" #define PATHSEP "/"
#endif #endif
#ifdef __cpp_lib_filesystem
// When std::filesystem is available, use it
#include <filesystem>
#undef GETCWD
#define GETCWD(BUF, SIZE) (std::filesystem::current_path().string().c_str())
#endif
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvar.h" #include "colvar.h"
#include "colvarbias_meta.h" #include "colvarbias_meta.h"
#include "colvars_memstream.h"
colvarbias_meta::colvarbias_meta(char const *key) colvarbias_meta::colvarbias_meta(char const *key)
@ -58,7 +62,6 @@ colvarbias_meta::colvarbias_meta(char const *key)
ebmeta_equil_steps = 0L; ebmeta_equil_steps = 0L;
replica_update_freq = 0;
replica_id.clear(); replica_id.clear();
} }
@ -392,11 +395,8 @@ colvarbias_meta::add_hill(colvarbias_meta::hill const &h)
// output to trajectory (if specified) // output to trajectory (if specified)
if (b_hills_traj) { if (b_hills_traj) {
// Open trajectory file or access the one already open // Save the current hill to a buffer for further traj output
std::ostream &hills_traj_os = hills_traj_os_buf << (hills.back()).output_traj();
cvm::proxy->output_stream(hills_traj_file_name());
hills_traj_os << (hills.back()).output_traj();
cvm::proxy->flush_output_stream(hills_traj_file_name());
} }
has_data = true; has_data = true;
@ -427,13 +427,10 @@ colvarbias_meta::delete_hill(hill_iter &h)
} }
if (b_hills_traj) { if (b_hills_traj) {
// output to the trajectory // Save the current hill to a buffer for further traj output
std::ostream &hills_traj_os = hills_traj_os_buf << "# DELETED this hill: "
cvm::proxy->output_stream(hills_traj_file_name()); << (hills.back()).output_traj()
hills_traj_os << "# DELETED this hill: " << "\n";
<< (hills.back()).output_traj()
<< "\n";
cvm::proxy->flush_output_stream(hills_traj_file_name());
} }
return hills.erase(h); return hills.erase(h);
@ -624,9 +621,9 @@ int colvarbias_meta::update_bias()
add_hill(hill(cvm::step_absolute(), hill_weight*hills_scale, add_hill(hill(cvm::step_absolute(), hill_weight*hills_scale,
colvar_values, colvar_sigmas, replica_id)); colvar_values, colvar_sigmas, replica_id));
std::ostream &replica_hills_os = std::ostream &replica_hills_os =
cvm::proxy->output_stream(replica_hills_file); cvm::proxy->output_stream(replica_hills_file, "replica hills file");
if (replica_hills_os) { if (replica_hills_os) {
replica_hills_os << hills.back(); write_hill(replica_hills_os, hills.back());
} else { } else {
return cvm::error("Error: in metadynamics bias \""+this->name+"\""+ return cvm::error("Error: in metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
@ -985,9 +982,9 @@ void colvarbias_meta::recount_hills_off_grid(colvarbias_meta::hill_iter h_first
int colvarbias_meta::replica_share() int colvarbias_meta::replica_share()
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
colvarproxy *proxy = cvm::proxy;
// sync with the other replicas (if needed) // sync with the other replicas (if needed)
if (comm == multiple_replicas) { if (comm == multiple_replicas) {
colvarproxy *proxy = cvm::main()->proxy;
// reread the replicas registry // reread the replicas registry
error_code |= update_replicas_registry(); error_code |= update_replicas_registry();
// empty the output buffer // empty the output buffer
@ -998,6 +995,12 @@ int colvarbias_meta::replica_share()
} }
size_t colvarbias_meta::replica_share_freq() const
{
return replica_update_freq;
}
int colvarbias_meta::update_replicas_registry() int colvarbias_meta::update_replicas_registry()
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -1299,21 +1302,40 @@ int colvarbias_meta::set_state_params(std::string const &state_conf)
} }
std::istream & colvarbias_meta::read_state_data(std::istream& is) template <typename IST, typename GT>
IST & colvarbias_meta::read_grid_data_template_(IST& is, std::string const &key,
GT *grid, GT *backup_grid)
{
auto const start_pos = is.tellg();
std::string key_in;
if (is >> key_in) {
if ((key != key_in) || !(grid->read_restart(is))) {
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
if (!rebin_grids) {
if ((backup_grid == nullptr) || (comm == single_replica)) {
cvm::error("Error: couldn't read grid data for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, "
"try enabling rebinGrids now to regenerate the grids.\n", COLVARS_INPUT_ERROR);
}
}
}
} else {
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
}
return is;
}
template <typename IST> IST &colvarbias_meta::read_state_data_template_(IST &is)
{ {
if (use_grids) { if (use_grids) {
if (expand_grids) {
// the boundaries of the colvars may have been changed; TODO:
// this reallocation is only for backward-compatibility, and may
// be deleted when grid_parameters (i.e. colvargrid's own
// internal reallocation) has kicked in
delete hills_energy;
delete hills_energy_gradients;
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
}
colvar_grid_scalar *hills_energy_backup = NULL; colvar_grid_scalar *hills_energy_backup = NULL;
colvar_grid_gradient *hills_energy_gradients_backup = NULL; colvar_grid_gradient *hills_energy_gradients_backup = NULL;
@ -1328,95 +1350,26 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
hills_energy_gradients = new colvar_grid_gradient(colvars); hills_energy_gradients = new colvar_grid_gradient(colvars);
} }
std::streampos const hills_energy_pos = is.tellg(); read_grid_data_template_<IST, colvar_grid_scalar>(is, "hills_energy", hills_energy,
std::string key; hills_energy_backup);
if (!(is >> key)) {
if (hills_energy_backup != NULL) { read_grid_data_template_<IST, colvar_grid_gradient>(
delete hills_energy; is, "hills_energy_gradients", hills_energy_gradients, hills_energy_gradients_backup);
delete hills_energy_gradients;
hills_energy = hills_energy_backup; if (is) {
hills_energy_gradients = hills_energy_gradients_backup; cvm::log(" successfully read the biasing potential and its gradients from grids.\n");
if (hills_energy_backup != nullptr) {
// Now that we have successfully updated the grids, delete the backup copies
delete hills_energy_backup;
delete hills_energy_gradients_backup;
} }
is.clear(); } else {
is.seekg(hills_energy_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is; return is;
} else if (!(key == std::string("hills_energy")) ||
!(hills_energy->read_restart(is))) {
is.clear();
is.seekg(hills_energy_pos, std::ios::beg);
if (!rebin_grids) {
if ((hills_energy_backup == NULL) || (comm == single_replica)) {
cvm::error("Error: couldn't read the energy grid for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, "
"enable rebinGrids now to regenerate the grids.\n");
} else {
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
is.setstate(std::ios::failbit);
return is;
}
}
}
std::streampos const hills_energy_gradients_pos = is.tellg();
if (!(is >> key)) {
if (hills_energy_backup != NULL) {
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
}
is.clear();
is.seekg(hills_energy_gradients_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
} else if (!(key == std::string("hills_energy_gradients")) ||
!(hills_energy_gradients->read_restart(is))) {
is.clear();
is.seekg(hills_energy_gradients_pos, std::ios::beg);
if (!rebin_grids) {
if ((hills_energy_backup == NULL) || (comm == single_replica)) {
cvm::error("Error: couldn't read the gradients grid for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, "
"enable rebinGrids now to regenerate the grids.\n");
} else {
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
is.setstate(std::ios::failbit);
return is;
}
}
}
if (cvm::debug())
cvm::log("Successfully read new grids for bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n");
cvm::log(" read biasing energy and forces from grids.\n");
if (hills_energy_backup != NULL) {
// now that we have successfully updated the grids, delete the
// backup copies
if (cvm::debug())
cvm::log("Deallocating the older grids.\n");
delete hills_energy_backup;
delete hills_energy_gradients_backup;
} }
} }
// Save references to the end of the list of existing hills, so that it can // Save references to the end of the list of existing hills, so that they can
// be cleared if hills are read successfully state // be cleared if hills are read successfully from the stream
bool const existing_hills = !hills.empty(); bool const existing_hills = !hills.empty();
size_t const old_hills_size = hills.size(); size_t const old_hills_size = hills.size();
hill_iter old_hills_end = hills.end(); hill_iter old_hills_end = hills.end();
@ -1430,17 +1383,20 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
while (read_hill(is)) { while (read_hill(is)) {
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Read a previously saved hill under the " cvm::log("Read a previously saved hill under the "
"metadynamics bias \""+ "metadynamics bias \"" +
this->name+"\", created at step "+ this->name + "\", created at step " + cvm::to_str((hills.back()).it) +
cvm::to_str((hills.back()).it)+".\n"); "; position in stream is " + cvm::to_str(is.tellg()) + ".\n");
} }
} }
is.clear(); is.clear();
new_hills_begin = hills.end(); new_hills_begin = hills.end();
cvm::log(" read "+cvm::to_str(hills.size() - old_hills_size)+ cvm::log(" successfully read "+cvm::to_str(hills.size() - old_hills_size)+
" additional explicit hills.\n"); " explicit hills from state.\n");
if (existing_hills) { if (existing_hills) {
// Prune any hills that pre-existed those just read
hills.erase(hills.begin(), old_hills_end); hills.erase(hills.begin(), old_hills_end);
hills_off_grid.erase(hills_off_grid.begin(), old_hills_off_grid_end); hills_off_grid.erase(hills_off_grid.begin(), old_hills_off_grid_end);
if (cvm::debug()) { if (cvm::debug()) {
@ -1449,6 +1405,46 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
} }
} }
// If rebinGrids is set, rebin the grids based on the current information
rebin_grids_after_restart();
if (use_grids) {
if (!hills_off_grid.empty()) {
cvm::log(cvm::to_str(hills_off_grid.size())+" hills are near the "
"grid boundaries: they will be computed analytically "
"and saved to the state files.\n");
}
}
colvarbias_ti::read_state_data(is);
if (cvm::debug())
cvm::log("colvarbias_meta::read_restart() done\n");
has_data = true;
if (comm == multiple_replicas) {
read_replica_files();
}
return is;
}
std::istream & colvarbias_meta::read_state_data(std::istream& is)
{
return read_state_data_template_<std::istream>(is);
}
cvm::memory_stream &colvarbias_meta::read_state_data(cvm::memory_stream &is)
{
return read_state_data_template_<cvm::memory_stream>(is);
}
void colvarbias_meta::rebin_grids_after_restart()
{
if (rebin_grids) { if (rebin_grids) {
// allocate new grids (based on the new boundaries and widths just // allocate new grids (based on the new boundaries and widths just
@ -1463,9 +1459,9 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
if (cvm::debug()) { if (cvm::debug()) {
std::ostringstream tmp_os; std::ostringstream tmp_os;
tmp_os << "hills_energy parameters:\n"; tmp_os << "hills_energy parameters:\n";
hills_energy->write_params(tmp_os); tmp_os << hills_energy->get_state_params();
tmp_os << "new_hills_energy parameters:\n"; tmp_os << "new_hills_energy parameters:\n";
new_hills_energy->write_params(tmp_os); tmp_os << new_hills_energy->get_state_params();
cvm::log(tmp_os.str()); cvm::log(tmp_os.str());
} }
@ -1495,114 +1491,182 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
if (!hills.empty()) if (!hills.empty())
recount_hills_off_grid(hills.begin(), hills.end(), hills_energy); recount_hills_off_grid(hills.begin(), hills.end(), hills_energy);
} }
}
if (use_grids) {
if (!hills_off_grid.empty()) { template <typename OST>
cvm::log(cvm::to_str(hills_off_grid.size())+" hills are near the " OST &colvarbias_meta::write_hill_template_(OST &os, colvarbias_meta::hill const &h)
"grid boundaries: they will be computed analytically " {
"and saved to the state files.\n"); bool const formatted = !std::is_same<OST, cvm::memory_stream>::value;
if (formatted) {
os.setf(std::ios::scientific, std::ios::floatfield);
}
write_state_data_key(os, "hill", false);
if (formatted)
os << "{\n";
write_state_data_key(os, "step", false);
if (formatted)
os << std::setw(cvm::it_width);
os << h.it;
if (formatted)
os << "\n";
write_state_data_key(os, "weight", false);
if (formatted)
os << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width);
os << h.W;
if (formatted)
os << "\n";
size_t i;
write_state_data_key(os, "centers", false);
for (i = 0; i < (h.centers).size(); i++) {
if (formatted)
os << " " << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width);
os << h.centers[i];
}
if (formatted)
os << "\n";
// For backward compatibility, write the widths instead of the sigmas
write_state_data_key(os, "widths", false);
for (i = 0; i < (h.sigmas).size(); i++) {
if (formatted)
os << " " << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width);
os << 2.0 * h.sigmas[i];
}
if (formatted)
os << "\n";
if (h.replica.size()) {
write_state_data_key(os, "replicaID", false);
os << h.replica;
if (formatted)
os << "\n";
}
if (formatted)
os << "}\n";
return os;
}
std::ostream &colvarbias_meta::write_hill(std::ostream &os, colvarbias_meta::hill const &h)
{
return write_hill_template_<std::ostream>(os, h);
}
cvm::memory_stream &colvarbias_meta::write_hill(cvm::memory_stream &os,
colvarbias_meta::hill const &h)
{
return write_hill_template_<cvm::memory_stream>(os, h);
}
template <typename IST> IST &hill_stream_error(IST &is, size_t start_pos, std::string const &key)
{
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
cvm::error("Error: in reading data for keyword \"" + key + "\" from stream.\n",
COLVARS_INPUT_ERROR);
return is;
}
template <typename IST> IST &colvarbias_meta::read_hill_template_(IST &is)
{
if (!is)
return is; // do nothing if failbit is set
bool const formatted = !std::is_same<IST, cvm::memory_stream>::value;
auto const start_pos = is.tellg();
std::string key;
if (!(is >> key) || (key != "hill")) {
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
return is;
}
if (formatted) {
std::string brace;
if (!(is >> brace) || (brace != "{")) {
return hill_stream_error<IST>(is, start_pos, "hill");
} }
} }
colvarbias_ti::read_state_data(is);
if (cvm::debug())
cvm::log("colvarbias_meta::read_restart() done\n");
has_data = true;
if (comm != single_replica) {
read_replica_files();
}
return is;
}
inline std::istream & reset_istream(std::istream &is, size_t start_pos)
{
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
std::istream & colvarbias_meta::read_hill(std::istream &is)
{
if (!is) return is; // do nothing if failbit is set
std::streampos const start_pos = is.tellg();
size_t i = 0;
std::string data;
if ( !(is >> read_block("hill", &data)) ) {
return reset_istream(is, start_pos);
}
std::istringstream data_is(data);
cvm::step_number h_it = 0L; cvm::step_number h_it = 0L;
cvm::real h_weight; cvm::real h_weight = 0.0;
std::vector<colvarvalue> h_centers(num_variables()); std::vector<colvarvalue> h_centers(num_variables());
for (i = 0; i < num_variables(); i++) { for (size_t i = 0; i < num_variables(); i++) {
h_centers[i].type(variables(i)->value()); h_centers[i].type(variables(i)->value());
} }
std::vector<cvm::real> h_sigmas(num_variables()); std::vector<cvm::real> h_sigmas(num_variables());
std::string h_replica; std::string h_replica;
std::string keyword; if (!read_state_data_key(is, "step") || !(is >> h_it)) {
while (data_is >> keyword) { return hill_stream_error<IST>(is, start_pos, "step");
}
if (keyword == "step") { if (read_state_data_key(is, "weight")) {
if ( !(data_is >> h_it)) { if (!(is >> h_weight)) {
return reset_istream(is, start_pos); return hill_stream_error<IST>(is, start_pos, "weight");
} }
if ((h_it <= state_file_step) && !restart_keep_hills) { }
if (cvm::debug())
cvm::log("Skipping a hill older than the state file for metadynamics bias \""+ if (read_state_data_key(is, "centers")) {
this->name+"\""+ for (size_t i = 0; i < num_variables(); i++) {
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n"); if (!(is >> h_centers[i])) {
return is; return hill_stream_error<IST>(is, start_pos, "centers");
} }
} }
}
if (keyword == "weight") { if (read_state_data_key(is, "widths")) {
if ( !(data_is >> h_weight)) { for (size_t i = 0; i < num_variables(); i++) {
return reset_istream(is, start_pos); if (!(is >> h_sigmas[i])) {
return hill_stream_error<IST>(is, start_pos, "widths");
}
// For backward compatibility, read the widths instead of the sigmas
h_sigmas[i] /= 2.0;
}
}
if (comm != single_replica) {
if (read_state_data_key(is, "replicaID")) {
if (!(is >> h_replica)) {
return hill_stream_error<IST>(is, start_pos, "replicaID");
}
if (h_replica != replica_id) {
cvm::error("Error: trying to read a hill created by replica \"" + h_replica +
"\" for replica \"" + replica_id + "\"; did you swap output files?\n",
COLVARS_INPUT_ERROR);
return hill_stream_error<IST>(is, start_pos, "replicaID");
} }
} }
}
if (keyword == "centers") { if (formatted) {
for (i = 0; i < num_variables(); i++) { std::string brace;
if ( !(data_is >> h_centers[i])) { if (!(is >> brace) || (brace != "}")) {
return reset_istream(is, start_pos); return hill_stream_error<IST>(is, start_pos, "hill");
}
}
} }
}
if (keyword == "widths") { if ((h_it <= state_file_step) && !restart_keep_hills) {
for (i = 0; i < num_variables(); i++) { if (cvm::debug())
if ( !(data_is >> h_sigmas[i])) { cvm::log("Skipping a hill older than the state file for metadynamics bias \"" + this->name +
return reset_istream(is, start_pos); "\"" + ((comm != single_replica) ? ", replica \"" + replica_id + "\"" : "") + "\n");
} return is;
// For backward compatibility, read the widths instead of the sigmas
h_sigmas[i] /= 2.0;
}
}
if (comm != single_replica) {
if (keyword == "replicaID") {
if ( !(data_is >> h_replica)) {
return reset_istream(is, start_pos);
}
if (h_replica != replica_id) {
cvm::error("Error: trying to read a hill created by replica \""+
h_replica+"\" for replica \""+replica_id+
"\"; did you swap output files?\n", COLVARS_INPUT_ERROR);
}
}
}
} }
hill_iter const hills_end = hills.end(); hill_iter const hills_end = hills.end();
@ -1617,7 +1681,7 @@ std::istream & colvarbias_meta::read_hill(std::istream &is)
// add this also to the list of hills that are off-grid, which will // add this also to the list of hills that are off-grid, which will
// be computed analytically // be computed analytically
cvm::real const min_dist = cvm::real const min_dist =
hills_energy->bin_distance_from_boundaries((hills.back()).centers, true); hills_energy->bin_distance_from_boundaries((hills.back()).centers, true);
if (min_dist < (3.0 * cvm::floor(hill_width)) + 1.0) { if (min_dist < (3.0 * cvm::floor(hill_width)) + 1.0) {
hills_off_grid.push_back(hills.back()); hills_off_grid.push_back(hills.back());
} }
@ -1628,6 +1692,18 @@ std::istream & colvarbias_meta::read_hill(std::istream &is)
} }
std::istream &colvarbias_meta::read_hill(std::istream &is)
{
return read_hill_template_<std::istream>(is);
}
cvm::memory_stream &colvarbias_meta::read_hill(cvm::memory_stream &is)
{
return read_hill_template_<cvm::memory_stream>(is);
}
int colvarbias_meta::setup_output() int colvarbias_meta::setup_output()
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -1644,7 +1720,10 @@ int colvarbias_meta::setup_output()
// TODO: one may want to specify the path manually for intricated filesystems? // TODO: one may want to specify the path manually for intricated filesystems?
char *pwd = new char[3001]; char *pwd = new char[3001];
if (GETCWD(pwd, 3000) == NULL) { if (GETCWD(pwd, 3000) == nullptr) {
if (pwd != nullptr) { //
delete[] pwd;
}
return cvm::error("Error: cannot get the path of the current working directory.\n", return cvm::error("Error: cannot get the path of the current working directory.\n",
COLVARS_BUG_ERROR); COLVARS_BUG_ERROR);
} }
@ -1701,7 +1780,7 @@ int colvarbias_meta::setup_output()
// if we're running without grids, use a growing list of "hills" files // if we're running without grids, use a growing list of "hills" files
// otherwise, just one state file and one "hills" file as buffer // otherwise, just one state file and one "hills" file as buffer
std::ostream &list_os = cvm::proxy->output_stream(replica_list_file); std::ostream &list_os = cvm::proxy->output_stream(replica_list_file, "replica list file");
if (list_os) { if (list_os) {
list_os << "stateFile " << replica_state_file << "\n"; list_os << "stateFile " << replica_state_file << "\n";
list_os << "hillsFile " << replica_hills_file << "\n"; list_os << "hillsFile " << replica_hills_file << "\n";
@ -1723,7 +1802,7 @@ int colvarbias_meta::setup_output()
if (b_hills_traj) { if (b_hills_traj) {
std::ostream &hills_traj_os = std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name()); cvm::proxy->output_stream(hills_traj_file_name(), "hills trajectory file");
if (!hills_traj_os) { if (!hills_traj_os) {
error_code |= COLVARS_FILE_ERROR; error_code |= COLVARS_FILE_ERROR;
} }
@ -1757,36 +1836,32 @@ std::string const colvarbias_meta::get_state_params() const
} }
std::ostream & colvarbias_meta::write_state_data(std::ostream& os) template <typename OST> OST &colvarbias_meta::write_state_data_template_(OST &os)
{ {
if (use_grids) { if (use_grids) {
// this is a very good time to project hills, if you haven't done // this is a very good time to project hills, if you haven't done
// it already! // it already!
project_hills(new_hills_begin, hills.end(), project_hills(new_hills_begin, hills.end(), hills_energy, hills_energy_gradients);
hills_energy, hills_energy_gradients);
new_hills_begin = hills.end(); new_hills_begin = hills.end();
// write down the grids to the restart file // write down the grids to the restart file
os << " hills_energy\n"; write_state_data_key(os, "hills_energy");
hills_energy->write_restart(os); hills_energy->write_restart(os);
os << " hills_energy_gradients\n"; write_state_data_key(os, "hills_energy_gradients");
hills_energy_gradients->write_restart(os); hills_energy_gradients->write_restart(os);
} }
if ( (!use_grids) || keep_hills ) { if ((!use_grids) || keep_hills) {
// write all hills currently in memory // write all hills currently in memory
for (std::list<hill>::const_iterator h = this->hills.begin(); for (std::list<hill>::const_iterator h = this->hills.begin(); h != this->hills.end(); h++) {
h != this->hills.end(); write_hill(os, *h);
h++) {
os << *h;
} }
} else { } else {
// write just those that are near the grid boundaries // write just those that are near the grid boundaries
for (std::list<hill>::const_iterator h = this->hills_off_grid.begin(); for (std::list<hill>::const_iterator h = this->hills_off_grid.begin();
h != this->hills_off_grid.end(); h != this->hills_off_grid.end(); h++) {
h++) { write_hill(os, *h);
os << *h;
} }
} }
@ -1795,6 +1870,18 @@ std::ostream & colvarbias_meta::write_state_data(std::ostream& os)
} }
std::ostream & colvarbias_meta::write_state_data(std::ostream& os)
{
return write_state_data_template_<std::ostream>(os);
}
cvm::memory_stream &colvarbias_meta::write_state_data(cvm::memory_stream &os)
{
return write_state_data_template_<cvm::memory_stream>(os);
}
int colvarbias_meta::write_state_to_replicas() int colvarbias_meta::write_state_to_replicas()
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -1816,6 +1903,15 @@ int colvarbias_meta::write_output_files()
if (dump_fes) { if (dump_fes) {
write_pmf(); write_pmf();
} }
if (b_hills_traj) {
std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name(), "hills trajectory file");
hills_traj_os << hills_traj_os_buf.str();
cvm::proxy->flush_output_stream(hills_traj_file_name());
// clear the buffer
hills_traj_os_buf.str("");
hills_traj_os_buf.clear();
}
return COLVARS_OK; return COLVARS_OK;
} }
@ -1915,7 +2011,7 @@ int colvarbias_meta::write_replica_state_file()
// Write to temporary state file // Write to temporary state file
std::string const tmp_state_file(replica_state_file+".tmp"); std::string const tmp_state_file(replica_state_file+".tmp");
error_code |= proxy->remove_file(tmp_state_file); error_code |= proxy->remove_file(tmp_state_file);
std::ostream &rep_state_os = cvm::proxy->output_stream(tmp_state_file); std::ostream &rep_state_os = cvm::proxy->output_stream(tmp_state_file, "temporary state file");
if (rep_state_os) { if (rep_state_os) {
if (!write_state(rep_state_os)) { if (!write_state(rep_state_os)) {
error_code |= cvm::error("Error: in writing to temporary file \""+ error_code |= cvm::error("Error: in writing to temporary file \""+
@ -1934,11 +2030,11 @@ int colvarbias_meta::reopen_replica_buffer_file()
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
colvarproxy *proxy = cvm::proxy; colvarproxy *proxy = cvm::proxy;
if (proxy->output_stream(replica_hills_file)) { if (proxy->output_stream(replica_hills_file, "replica hills file")) {
error_code |= proxy->close_output_stream(replica_hills_file); error_code |= proxy->close_output_stream(replica_hills_file);
} }
error_code |= proxy->remove_file(replica_hills_file); error_code |= proxy->remove_file(replica_hills_file);
std::ostream &replica_hills_os = proxy->output_stream(replica_hills_file); std::ostream &replica_hills_os = proxy->output_stream(replica_hills_file, "replica hills file");
if (replica_hills_os) { if (replica_hills_os) {
replica_hills_os.setf(std::ios::scientific, std::ios::floatfield); replica_hills_os.setf(std::ios::scientific, std::ios::floatfield);
} else { } else {
@ -2037,43 +2133,3 @@ colvarbias_meta::hill::operator = (colvarbias_meta::hill const &h)
colvarbias_meta::hill::~hill() colvarbias_meta::hill::~hill()
{} {}
std::ostream & operator << (std::ostream &os, colvarbias_meta::hill const &h)
{
os.setf(std::ios::scientific, std::ios::floatfield);
os << "hill {\n";
os << " step " << std::setw(cvm::it_width) << h.it << "\n";
os << " weight "
<< std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width)
<< h.W << "\n";
if (h.replica.size())
os << " replicaID " << h.replica << "\n";
size_t i;
os << " centers ";
for (i = 0; i < (h.centers).size(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< h.centers[i];
}
os << "\n";
// For backward compatibility, write the widths instead of the sigmas
os << " widths ";
for (i = 0; i < (h.sigmas).size(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< 2.0 * h.sigmas[i];
}
os << "\n";
os << "}\n";
return os;
}

View File

@ -17,6 +17,7 @@
#include "colvarbias.h" #include "colvarbias.h"
#include "colvargrid.h" #include "colvargrid.h"
/// Metadynamics bias (implementation of \link colvarbias \endlink) /// Metadynamics bias (implementation of \link colvarbias \endlink)
class colvarbias_meta class colvarbias_meta
: public virtual colvarbias, : public virtual colvarbias,
@ -51,14 +52,32 @@ public:
virtual int update_bias(); virtual int update_bias();
virtual int update_grid_data(); virtual int update_grid_data();
virtual int replica_share(); virtual int replica_share();
virtual size_t replica_share_freq() const;
virtual int calc_energy(std::vector<colvarvalue> const *values); virtual int calc_energy(std::vector<colvarvalue> const *values);
virtual int calc_forces(std::vector<colvarvalue> const *values); virtual int calc_forces(std::vector<colvarvalue> const *values);
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &state_conf); virtual int set_state_params(std::string const &state_conf);
virtual std::ostream & write_state_data(std::ostream &os);
virtual std::istream & read_state_data(std::istream &os); virtual std::ostream &write_state_data(std::ostream &os);
virtual cvm::memory_stream &write_state_data(cvm::memory_stream &os);
virtual std::istream &read_state_data(std::istream &is);
virtual cvm::memory_stream &read_state_data(cvm::memory_stream &is);
private:
template <typename IST, typename GT>
IST &read_grid_data_template_(IST &is, std::string const &key, GT *grid, GT *backup_grid);
template <typename IST> IST &read_state_data_template_(IST &is);
template <typename OST> OST &write_state_data_template_(OST &os);
public:
/// Function called by read_state_data() to execute rebinning (if requested)
void rebin_grids_after_restart();
virtual int setup_output(); virtual int setup_output();
virtual int write_output_files(); virtual int write_output_files();
@ -105,11 +124,24 @@ protected:
/// Regenerate the hills_off_grid list /// Regenerate the hills_off_grid list
void recount_hills_off_grid(hill_iter h_first, hill_iter h_last, void recount_hills_off_grid(hill_iter h_first, hill_iter h_last,
colvar_grid_scalar *ge); colvar_grid_scalar *ge);
/// Read a hill from a file template <typename OST> OST &write_hill_template_(OST &os, colvarbias_meta::hill const &h);
/// Write a hill to a formatted stream
std::ostream &write_hill(std::ostream &os, hill const &h);
/// Write a hill to an unformatted stream
cvm::memory_stream &write_hill(cvm::memory_stream &os, hill const &h);
template <typename IST> IST &read_hill_template_(IST &is);
/// Read a new hill from a formatted stream
std::istream & read_hill(std::istream &is); std::istream & read_hill(std::istream &is);
/// Read a new hill from an unformatted stream
cvm::memory_stream & read_hill(cvm::memory_stream &is);
/// \brief Add a new hill; if a .hills trajectory is written, /// \brief Add a new hill; if a .hills trajectory is written,
/// write it there; if there is more than one replica, communicate /// write it there; if there is more than one replica, communicate
/// it to the others /// it to the others
@ -230,7 +262,7 @@ protected:
std::vector<colvarbias_meta *> replicas; std::vector<colvarbias_meta *> replicas;
/// \brief Frequency at which data the "mirror" biases are updated /// \brief Frequency at which data the "mirror" biases are updated
size_t replica_update_freq; size_t replica_update_freq = 0;
/// List of replicas (and their output list files): contents are /// List of replicas (and their output list files): contents are
/// copied into replicas_registry for convenience /// copied into replicas_registry for convenience
@ -258,6 +290,8 @@ protected:
/// Position within replica_hills_file (when reading it) /// Position within replica_hills_file (when reading it)
std::streampos replica_hills_file_pos; std::streampos replica_hills_file_pos;
/// Cache of the hills trajectory
std::ostringstream hills_traj_os_buf;
}; };
@ -399,9 +433,6 @@ public:
/// Represent the hill ina string suitable for a trajectory file /// Represent the hill ina string suitable for a trajectory file
std::string output_traj(); std::string output_traj();
/// Write the hill to an output stream
friend std::ostream & operator << (std::ostream &os, hill const &h);
}; };

View File

@ -27,7 +27,10 @@ colvarbias_restraint::colvarbias_restraint(char const *key)
int colvarbias_restraint::init(std::string const &conf) int colvarbias_restraint::init(std::string const &conf)
{ {
colvarbias::init(conf); int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
enable(f_cvb_apply_force); enable(f_cvb_apply_force);
colvarbias_ti::init(conf); colvarbias_ti::init(conf);
@ -202,6 +205,8 @@ int colvarbias_restraint_moving::init(std::string const &conf)
first_step = cvm::step_absolute(); first_step = cvm::step_absolute();
cvm::log("Initial step for restraint change: " + cvm::to_str(first_step) + "\n");
get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps); get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps);
if (!target_nsteps) { if (!target_nsteps) {
cvm::error("Error: targetNumSteps must be non-zero.\n", COLVARS_INPUT_ERROR); cvm::error("Error: targetNumSteps must be non-zero.\n", COLVARS_INPUT_ERROR);
@ -232,10 +237,9 @@ std::string const colvarbias_restraint_moving::get_state_params() const
std::ostringstream os; std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield); os.setf(std::ios::scientific, std::ios::floatfield);
if (b_chg_centers || b_chg_force_k) { if (b_chg_centers || b_chg_force_k) {
// TODO move this os << "firstStep " << std::setw(cvm::it_width) << first_step << "\n";
if (target_nstages) { if (target_nstages) {
os << "stage " << std::setw(cvm::it_width) os << "stage " << std::setw(cvm::it_width) << stage << "\n";
<< stage << "\n";
} }
} }
return os.str(); return os.str();
@ -245,6 +249,12 @@ std::string const colvarbias_restraint_moving::get_state_params() const
int colvarbias_restraint_moving::set_state_params(std::string const &conf) int colvarbias_restraint_moving::set_state_params(std::string const &conf)
{ {
if (b_chg_centers || b_chg_force_k) { if (b_chg_centers || b_chg_force_k) {
auto first_step_flags = colvarparse::parse_restart;
if (cvm::main()->restart_version_number() > 20230906) {
// Only require the first step when the code could produce it
first_step_flags = colvarparse::parse_restart | colvarparse::parse_required;
}
get_keyval(conf, "firstStep", first_step, first_step, first_step_flags);
if (target_nstages) { if (target_nstages) {
get_keyval(conf, "stage", stage, stage, get_keyval(conf, "stage", stage, stage,
colvarparse::parse_restart | colvarparse::parse_required); colvarparse::parse_restart | colvarparse::parse_required);
@ -837,18 +847,6 @@ int colvarbias_restraint_harmonic::set_state_params(std::string const &conf)
} }
std::ostream & colvarbias_restraint_harmonic::write_state_data(std::ostream &os)
{
return colvarbias_ti::write_state_data(os);
}
std::istream & colvarbias_restraint_harmonic::read_state_data(std::istream &is)
{
return colvarbias_ti::read_state_data(is);
}
std::ostream & colvarbias_restraint_harmonic::write_traj_label(std::ostream &os) std::ostream & colvarbias_restraint_harmonic::write_traj_label(std::ostream &os)
{ {
colvarbias_restraint::write_traj_label(os); colvarbias_restraint::write_traj_label(os);
@ -1136,18 +1134,6 @@ int colvarbias_restraint_harmonic_walls::set_state_params(std::string const &con
} }
std::ostream & colvarbias_restraint_harmonic_walls::write_state_data(std::ostream &os)
{
return colvarbias_ti::write_state_data(os);
}
std::istream & colvarbias_restraint_harmonic_walls::read_state_data(std::istream &is)
{
return colvarbias_ti::read_state_data(is);
}
std::ostream & colvarbias_restraint_harmonic_walls::write_traj_label(std::ostream &os) std::ostream & colvarbias_restraint_harmonic_walls::write_traj_label(std::ostream &os)
{ {
colvarbias_restraint::write_traj_label(os); colvarbias_restraint::write_traj_label(os);
@ -1293,18 +1279,6 @@ int colvarbias_restraint_linear::set_state_params(std::string const &conf)
} }
std::ostream & colvarbias_restraint_linear::write_state_data(std::ostream &os)
{
return colvarbias_ti::write_state_data(os);
}
std::istream & colvarbias_restraint_linear::read_state_data(std::istream &is)
{
return colvarbias_ti::read_state_data(is);
}
std::ostream & colvarbias_restraint_linear::write_traj_label(std::ostream &os) std::ostream & colvarbias_restraint_linear::write_traj_label(std::ostream &os)
{ {
colvarbias_restraint::write_traj_label(os); colvarbias_restraint::write_traj_label(os);
@ -1338,7 +1312,10 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
colvarbias::init(conf); int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
enable(f_cvb_apply_force); enable(f_cvb_apply_force);
cvm::main()->cite_feature("histogramRestraint colvar bias implementation"); cvm::main()->cite_feature("histogramRestraint colvar bias implementation");

View File

@ -38,9 +38,6 @@ public:
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &conf); virtual int set_state_params(std::string const &conf);
// virtual std::ostream & write_state_data(std::ostream &os);
// virtual std::istream & read_state_data(std::istream &os);
virtual std::ostream & write_traj_label(std::ostream &os); virtual std::ostream & write_traj_label(std::ostream &os);
virtual std::ostream & write_traj(std::ostream &os); virtual std::ostream & write_traj(std::ostream &os);
@ -242,8 +239,6 @@ public:
virtual int update(); virtual int update();
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &conf); virtual int set_state_params(std::string const &conf);
virtual std::ostream & write_state_data(std::ostream &os);
virtual std::istream & read_state_data(std::istream &os);
virtual std::ostream & write_traj_label(std::ostream &os); virtual std::ostream & write_traj_label(std::ostream &os);
virtual std::ostream & write_traj(std::ostream &os); virtual std::ostream & write_traj(std::ostream &os);
virtual int change_configuration(std::string const &conf); virtual int change_configuration(std::string const &conf);
@ -269,8 +264,6 @@ public:
virtual int update(); virtual int update();
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &conf); virtual int set_state_params(std::string const &conf);
virtual std::ostream & write_state_data(std::ostream &os);
virtual std::istream & read_state_data(std::istream &os);
virtual std::ostream & write_traj_label(std::ostream &os); virtual std::ostream & write_traj_label(std::ostream &os);
virtual std::ostream & write_traj(std::ostream &os); virtual std::ostream & write_traj(std::ostream &os);
@ -311,8 +304,6 @@ public:
virtual std::string const get_state_params() const; virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &conf); virtual int set_state_params(std::string const &conf);
virtual std::ostream & write_state_data(std::ostream &os);
virtual std::istream & read_state_data(std::istream &os);
virtual std::ostream & write_traj_label(std::ostream &os); virtual std::ostream & write_traj_label(std::ostream &os);
virtual std::ostream & write_traj(std::ostream &os); virtual std::ostream & write_traj(std::ostream &os);

View File

@ -19,45 +19,40 @@
colvar::cvc::cvc() colvar::cvc::cvc()
{ {
description = "uninitialized colvar component"; description = "uninitialized colvar component";
b_try_scalable = true;
sup_coeff = 1.0;
sup_np = 1;
period = 0.0;
wrap_center = 0.0;
width = 0.0;
cvc::init_dependencies(); cvc::init_dependencies();
} }
colvar::cvc::cvc(std::string const &conf) int colvar::cvc::update_description()
{ {
description = "uninitialized colvar component"; if (name.size() > 0) {
b_try_scalable = true; description = "cvc \"" + name + "\"";
sup_coeff = 1.0; } else {
sup_np = 1; description = "unnamed cvc";
period = 0.0; }
wrap_center = 0.0; description += " of type \"" + function_type() + "\"";
width = 0.0; return COLVARS_OK;
init_dependencies(); }
colvar::cvc::init(conf);
std::string colvar::cvc::function_type() const
{
if (function_types.empty()) {
return "unset";
}
return function_types.back();
} }
int colvar::cvc::set_function_type(std::string const &type) int colvar::cvc::set_function_type(std::string const &type)
{ {
function_type = type; function_types.push_back(type);
if (function_types.size() == 0) { update_description();
function_types.push_back(function_type); cvm::main()->cite_feature(function_types[0]+" colvar component");
} else {
if (function_types.back() != function_type) {
function_types.push_back(function_type);
}
}
for (size_t i = function_types.size()-1; i > 0; i--) { for (size_t i = function_types.size()-1; i > 0; i--) {
cvm::main()->cite_feature(function_types[i]+" colvar component"+ cvm::main()->cite_feature(function_types[i]+" colvar component"+
" (derived from "+function_types[i-1]+")"); " (derived from "+function_types[i-1]+")");
} }
cvm::main()->cite_feature(function_types[0]+" colvar component");
return COLVARS_OK; return COLVARS_OK;
} }
@ -67,6 +62,8 @@ int colvar::cvc::init(std::string const &conf)
if (cvm::debug()) if (cvm::debug())
cvm::log("Initializing cvc base object.\n"); cvm::log("Initializing cvc base object.\n");
int error_code = COLVARS_OK;
std::string const old_name(name); std::string const old_name(name);
if (name.size() > 0) { if (name.size() > 0) {
@ -74,18 +71,14 @@ int colvar::cvc::init(std::string const &conf)
} }
if (get_keyval(conf, "name", name, name)) { if (get_keyval(conf, "name", name, name)) {
if (name.size() > 0) {
description = "cvc \"" + name + "\" of type " + function_type;
} else {
description = "unnamed cvc";
}
if ((name != old_name) && (old_name.size() > 0)) { if ((name != old_name) && (old_name.size() > 0)) {
cvm::error("Error: cannot rename component \""+old_name+ error_code |= cvm::error("Error: cannot rename component \"" + old_name +
"\" after initialization (new name = \""+name+"\")", "\" after initialization (new name = \"" + name + "\")",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
name = old_name; name = old_name;
} }
} }
update_description();
get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff); get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff);
get_keyval(conf, "componentExp", sup_np, sup_np); get_keyval(conf, "componentExp", sup_np, sup_np);
@ -102,6 +95,24 @@ int colvar::cvc::init(std::string const &conf)
register_param("period", reinterpret_cast<void *>(&period)); register_param("period", reinterpret_cast<void *>(&period));
register_param("wrapAround", reinterpret_cast<void *>(&wrap_center)); register_param("wrapAround", reinterpret_cast<void *>(&wrap_center));
if (period != 0.0) {
if (!is_available(f_cvc_periodic)) {
error_code |=
cvm::error("Error: invalid use of period and/or "
"wrapAround in a \"" +
function_type() + "\" component.\n" + "Period: " + cvm::to_str(period) +
" wrapAround: " + cvm::to_str(wrap_center),
COLVARS_INPUT_ERROR);
} else {
enable(f_cvc_periodic);
}
}
if ((wrap_center != 0.0) && !is_enabled(f_cvc_periodic)) {
error_code |= cvm::error("Error: wrapAround was defined for a non-periodic component.\n",
COLVARS_INPUT_ERROR);
}
get_keyval_feature(this, conf, "debugGradients", get_keyval_feature(this, conf, "debugGradients",
f_cvc_debug_gradient, false, parse_silent); f_cvc_debug_gradient, false, parse_silent);
@ -119,7 +130,7 @@ int colvar::cvc::init(std::string const &conf)
if (cvm::debug()) if (cvm::debug())
cvm::log("Done initializing cvc base object.\n"); cvm::log("Done initializing cvc base object.\n");
return cvm::get_error(); return error_code;
} }
@ -157,10 +168,13 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
char const *group_key, char const *group_key,
bool optional) bool optional)
{ {
cvm::atom_group *group = NULL; int error_code = COLVARS_OK;
cvm::atom_group *group = nullptr;
std::string group_conf; std::string group_conf;
if (key_lookup(conf, group_key, &group_conf)) { if (key_lookup(conf, group_key, &group_conf)) {
group = new cvm::atom_group(group_key); group = new cvm::atom_group(group_key);
if (b_try_scalable) { if (b_try_scalable) {
@ -177,31 +191,42 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
// TODO check for other types of parallelism here // TODO check for other types of parallelism here
} }
if (group_conf.size() == 0) { if (group_conf.empty()) {
cvm::error("Error: atom group \""+group->key+ error_code |= cvm::error("Error: atom group \"" + group->key + "\" has no definition.\n",
"\" is set, but has no definition.\n", COLVARS_INPUT_ERROR);
COLVARS_INPUT_ERROR); delete group;
group = nullptr;
// Silence unused variable warning; TODO stop returning a pointer
(void) error_code;
return group; return group;
} }
cvm::increase_depth(); cvm::increase_depth();
if (group->parse(group_conf) == COLVARS_OK) { error_code |= group->parse(group_conf);
if (error_code != COLVARS_OK) {
error_code |=
cvm::error("Error: in definition of atom group \"" + std::string(group_key) + "\".",
COLVARS_INPUT_ERROR);
delete group;
group = nullptr;
} else {
register_atom_group(group); register_atom_group(group);
} error_code |= group->check_keywords(group_conf, group_key);
group->check_keywords(group_conf, group_key);
if (cvm::get_error()) {
cvm::error("Error parsing definition for atom group \""+
std::string(group_key)+"\".", COLVARS_INPUT_ERROR);
} }
cvm::decrease_depth(); cvm::decrease_depth();
} else { } else {
if (! optional) {
cvm::error("Error: definition for atom group \""+ if (!optional) {
std::string(group_key)+"\" not found.\n"); error_code |=
cvm::error("Error: atom group \"" + std::string(group_key) + "\" is required.\n",
COLVARS_INPUT_ERROR);
} }
} }
// Silence unused variable warning; TODO stop returning a pointer
(void) error_code;
return group; return group;
} }
@ -228,6 +253,8 @@ int colvar::cvc::init_dependencies() {
init_feature(f_cvc_upper_boundary, "defined_upper_boundary", f_type_static); init_feature(f_cvc_upper_boundary, "defined_upper_boundary", f_type_static);
init_feature(f_cvc_explicit_atom_groups, "explicit_atom_groups", f_type_static);
init_feature(f_cvc_gradient, "gradient", f_type_dynamic); init_feature(f_cvc_gradient, "gradient", f_type_dynamic);
init_feature(f_cvc_explicit_gradient, "explicit_gradient", f_type_static); init_feature(f_cvc_explicit_gradient, "explicit_gradient", f_type_static);
@ -264,6 +291,7 @@ int colvar::cvc::init_dependencies() {
init_feature(f_cvc_collect_atom_ids, "collect_atom_ids", f_type_dynamic); init_feature(f_cvc_collect_atom_ids, "collect_atom_ids", f_type_dynamic);
require_feature_children(f_cvc_collect_atom_ids, f_ag_collect_atom_ids); require_feature_children(f_cvc_collect_atom_ids, f_ag_collect_atom_ids);
require_feature_self(f_cvc_collect_atom_ids, f_cvc_explicit_atom_groups);
// TODO only enable this when f_ag_scalable can be turned on for a pre-initialized group // TODO only enable this when f_ag_scalable can be turned on for a pre-initialized group
// require_feature_children(f_cvc_scalable, f_ag_scalable); // require_feature_children(f_cvc_scalable, f_ag_scalable);
@ -281,7 +309,7 @@ int colvar::cvc::init_dependencies() {
// default as available, not enabled // default as available, not enabled
// except dynamic features which default as unavailable // except dynamic features which default as unavailable
feature_states.reserve(f_cvc_ntot); feature_states.reserve(f_cvc_ntot);
for (i = 0; i < colvardeps::f_cvc_ntot; i++) { for (i = feature_states.size(); i < colvardeps::f_cvc_ntot; i++) {
bool avail = is_dynamic(i) ? false : true; bool avail = is_dynamic(i) ? false : true;
feature_states.push_back(feature_state(avail, false)); feature_states.push_back(feature_state(avail, false));
} }
@ -292,6 +320,8 @@ int colvar::cvc::init_dependencies() {
feature_states[f_cvc_gradient].available = true; feature_states[f_cvc_gradient].available = true;
feature_states[f_cvc_collect_atom_ids].available = true; feature_states[f_cvc_collect_atom_ids].available = true;
feature_states[f_cvc_periodic].available = false;
// CVCs are enabled from the start - get disabled based on flags // CVCs are enabled from the start - get disabled based on flags
enable(f_cvc_active); enable(f_cvc_active);
@ -314,7 +344,7 @@ int colvar::cvc::init_dependencies() {
int colvar::cvc::setup() int colvar::cvc::setup()
{ {
description = "cvc " + name; update_description();
return COLVARS_OK; return COLVARS_OK;
} }
@ -349,6 +379,7 @@ void colvar::cvc::init_as_angle()
void colvar::cvc::init_as_periodic_angle() void colvar::cvc::init_as_periodic_angle()
{ {
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
provide(f_cvc_periodic);
enable(f_cvc_periodic); enable(f_cvc_periodic);
period = 360.0; period = 360.0;
init_scalar_boundaries(-180.0, 180.0); init_scalar_boundaries(-180.0, 180.0);
@ -372,6 +403,7 @@ void colvar::cvc::register_atom_group(cvm::atom_group *ag)
{ {
atom_groups.push_back(ag); atom_groups.push_back(ag);
add_child(ag); add_child(ag);
enable(f_cvc_explicit_atom_groups);
} }
@ -411,29 +443,21 @@ int colvar::cvc::set_param(std::string const &param_name,
void colvar::cvc::read_data() void colvar::cvc::read_data()
{ {
size_t ig; if (is_enabled(f_cvc_explicit_atom_groups)) {
for (ig = 0; ig < atom_groups.size(); ig++) { for (auto agi = atom_groups.begin(); agi != atom_groups.end(); agi++) {
cvm::atom_group &atoms = *(atom_groups[ig]); cvm::atom_group &atoms = *(*agi);
atoms.reset_atoms_data(); atoms.reset_atoms_data();
atoms.read_positions(); atoms.read_positions();
atoms.calc_required_properties(); atoms.calc_required_properties();
// each atom group will take care of its own fitting_group, if defined // each atom group will take care of its own fitting_group, if defined
}
} }
//// Don't try to get atom velocities, as no back-end currently implements it
// if (tasks[task_output_velocity] && !tasks[task_fdiff_velocity]) {
// for (i = 0; i < cvcs.size(); i++) {
// for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
// cvcs[i]->atom_groups[ig]->read_velocities();
// }
// }
// }
} }
std::vector<std::vector<int> > colvar::cvc::get_atom_lists() std::vector<std::vector<int>> colvar::cvc::get_atom_lists()
{ {
std::vector<std::vector<int> > lists; std::vector<std::vector<int>> lists;
std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin(); std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin();
for ( ; agi != atom_groups.end(); ++agi) { for ( ; agi != atom_groups.end(); ++agi) {
@ -462,12 +486,12 @@ void colvar::cvc::collect_gradients(std::vector<int> const &atom_ids, std::vecto
// If necessary, apply inverse rotation to get atomic // If necessary, apply inverse rotation to get atomic
// gradient in the laboratory frame // gradient in the laboratory frame
if (ag.is_enabled(f_ag_rotate)) { if (ag.is_enabled(f_ag_rotate)) {
cvm::rotation const rot_inv = ag.rot.inverse(); const auto rot_inv = ag.rot.inverse().matrix();
for (size_t k = 0; k < ag.size(); k++) { for (size_t k = 0; k < ag.size(); k++) {
size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(), size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
ag[k].id) - atom_ids.begin(); ag[k].id) - atom_ids.begin();
atomic_gradients[a] += coeff * rot_inv.rotate(ag[k].grad); atomic_gradients[a] += coeff * (rot_inv * ag[k].grad);
} }
} else { } else {
@ -494,7 +518,7 @@ void colvar::cvc::collect_gradients(std::vector<int> const &atom_ids, std::vecto
void colvar::cvc::calc_force_invgrads() void colvar::cvc::calc_force_invgrads()
{ {
cvm::error("Error: calculation of inverse gradients is not implemented " cvm::error("Error: calculation of inverse gradients is not implemented "
"for colvar components of type \""+function_type+"\".\n", "for colvar components of type \""+function_type()+"\".\n",
COLVARS_NOT_IMPLEMENTED); COLVARS_NOT_IMPLEMENTED);
} }
@ -502,7 +526,7 @@ void colvar::cvc::calc_force_invgrads()
void colvar::cvc::calc_Jacobian_derivative() void colvar::cvc::calc_Jacobian_derivative()
{ {
cvm::error("Error: calculation of inverse gradients is not implemented " cvm::error("Error: calculation of inverse gradients is not implemented "
"for colvar components of type \""+function_type+"\".\n", "for colvar components of type \""+function_type()+"\".\n",
COLVARS_NOT_IMPLEMENTED); COLVARS_NOT_IMPLEMENTED);
} }
@ -515,6 +539,18 @@ void colvar::cvc::calc_fit_gradients()
} }
void colvar::cvc::apply_force(colvarvalue const &cvforce)
{
if (is_enabled(f_cvc_explicit_atom_groups)) {
for (auto agi = atom_groups.begin(); agi != atom_groups.end(); agi++) {
if (!(*agi)->noforce) {
(*agi)->apply_colvar_force(cvforce);
}
}
}
}
void colvar::cvc::debug_gradients() void colvar::cvc::debug_gradients()
{ {
// this function should work for any scalar cvc: // this function should work for any scalar cvc:
@ -528,8 +564,8 @@ void colvar::cvc::debug_gradients()
cvm::atom_group *group = atom_groups[ig]; cvm::atom_group *group = atom_groups[ig];
if (group->b_dummy) continue; if (group->b_dummy) continue;
cvm::rotation const rot_0 = group->rot; const auto rot_0 = group->rot.matrix();
cvm::rotation const rot_inv = group->rot.inverse(); const auto rot_inv = group->rot.inverse().matrix();
cvm::real x_0 = x.real_value; cvm::real x_0 = x.real_value;
if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0]; if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0];
@ -550,7 +586,7 @@ void colvar::cvc::debug_gradients()
cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) + cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) +
"[" + cvm::to_str(j) + "] = " + "[" + cvm::to_str(j) + "] = " +
(group->is_enabled(f_ag_rotate) ? (group->is_enabled(f_ag_rotate) ?
cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) : cvm::to_str(rot_0 * (group_for_fit->fit_gradients[j])) :
cvm::to_str(group_for_fit->fit_gradients[j]))); cvm::to_str(group_for_fit->fit_gradients[j])));
} }
} }
@ -561,7 +597,7 @@ void colvar::cvc::debug_gradients()
// tests are best conducted in the unrotated (simulation) frame // tests are best conducted in the unrotated (simulation) frame
cvm::rvector const atom_grad = (group->is_enabled(f_ag_rotate) ? cvm::rvector const atom_grad = (group->is_enabled(f_ag_rotate) ?
rot_inv.rotate((*group)[ia].grad) : rot_inv * ((*group)[ia].grad) :
(*group)[ia].grad); (*group)[ia].grad);
gradient_sum += atom_grad; gradient_sum += atom_grad;
@ -634,34 +670,43 @@ void colvar::cvc::debug_gradients()
} }
cvm::real colvar::cvc::dist2(colvarvalue const &x1, cvm::real colvar::cvc::dist2(colvarvalue const &x1, colvarvalue const &x2) const
colvarvalue const &x2) const
{ {
return x1.dist2(x2); cvm::real diff = x1.real_value - x2.real_value;
if (is_enabled(f_cvc_periodic)) {
cvm::real const shift = cvm::floor(diff / period + 0.5);
diff -= shift * period;
}
return diff * diff;
} }
colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1, colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1, colvarvalue const &x2) const
colvarvalue const &x2) const
{ {
return x1.dist2_grad(x2); cvm::real diff = x1.real_value - x2.real_value;
if (is_enabled(f_cvc_periodic)) {
cvm::real const shift = cvm::floor(diff / period + 0.5);
diff -= shift * period;
}
return 2.0 * diff;
} }
colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1, colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1, colvarvalue const &x2) const
colvarvalue const &x2) const
{ {
return x2.dist2_grad(x1); return cvc::dist2_lgrad(x1, x2);
} }
void colvar::cvc::wrap(colvarvalue & /* x_unwrapped */) const void colvar::cvc::wrap(colvarvalue &x_unwrapped) const
{ {
return; if (is_enabled(f_cvc_periodic)) {
cvm::real const shift = cvm::floor((x_unwrapped.real_value - wrap_center) / period + 0.5);
x_unwrapped.real_value -= shift * period;
}
} }
// Static members // Static members
std::vector<colvardeps::feature *> colvar::cvc::cvc_features; std::vector<colvardeps::feature *> colvar::cvc::cvc_features;

File diff suppressed because it is too large Load Diff

View File

@ -12,13 +12,11 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::alch_lambda::alch_lambda(std::string const &conf) colvar::alch_lambda::alch_lambda()
: cvc(conf)
{ {
set_function_type("alchLambda"); set_function_type("alchLambda");
@ -56,12 +54,9 @@ void colvar::alch_lambda::apply_force(colvarvalue const & /* force */)
cvm::proxy->set_alch_lambda(x.real_value); cvm::proxy->set_alch_lambda(x.real_value);
} }
simple_scalar_dist_functions(alch_lambda)
colvar::alch_Flambda::alch_Flambda()
colvar::alch_Flambda::alch_Flambda(std::string const &conf)
: cvc(conf)
{ {
set_function_type("alch_Flambda"); set_function_type("alch_Flambda");
@ -103,4 +98,3 @@ void colvar::alch_Flambda::apply_force(colvarvalue const &force)
cvm::proxy->indirect_lambda_biasing_force += d2E_dlambda2 * f; cvm::proxy->indirect_lambda_biasing_force += d2E_dlambda2 * f;
} }
simple_scalar_dist_functions(alch_Flambda)

View File

@ -12,8 +12,7 @@
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::angle::angle(std::string const &conf) colvar::angle::angle()
: cvc(conf)
{ {
set_function_type("angle"); set_function_type("angle");
init_as_angle(); init_as_angle();
@ -21,26 +20,25 @@ colvar::angle::angle(std::string const &conf)
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
enable(f_cvc_com_based); enable(f_cvc_com_based);
}
int colvar::angle::init(std::string const &conf)
{
int error_code = cvc::init(conf);
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2"); group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3"); group3 = parse_group(conf, "group3");
init_total_force_params(conf); error_code |= init_total_force_params(conf);
return error_code;
} }
colvar::angle::angle(cvm::atom const &a1, colvar::angle::angle(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3) : angle()
cvm::atom const &a2,
cvm::atom const &a3)
{ {
set_function_type("angle");
init_as_angle();
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1)); group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2)); group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
group3 = new cvm::atom_group(std::vector<cvm::atom>(1, a3)); group3 = new cvm::atom_group(std::vector<cvm::atom>(1, a3));
@ -120,52 +118,6 @@ void colvar::angle::calc_Jacobian_derivative()
} }
void colvar::angle::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
if (!group3->noforce)
group3->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(angle)
colvar::dipole_angle::dipole_angle(std::string const &conf)
: cvc(conf)
{
set_function_type("dipoleAngle");
init_as_angle();
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3");
init_total_force_params(conf);
}
colvar::dipole_angle::dipole_angle(cvm::atom const &a1,
cvm::atom const &a2,
cvm::atom const &a3)
{
set_function_type("dipoleAngle");
init_as_angle();
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
group3 = new cvm::atom_group(std::vector<cvm::atom>(1, a3));
register_atom_group(group1);
register_atom_group(group2);
register_atom_group(group3);
}
colvar::dipole_angle::dipole_angle() colvar::dipole_angle::dipole_angle()
{ {
@ -174,6 +126,19 @@ colvar::dipole_angle::dipole_angle()
} }
int colvar::dipole_angle::init(std::string const &conf)
{
int error_code = cvc::init(conf);
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3");
error_code |= init_total_force_params(conf);
return error_code;
}
void colvar::dipole_angle::calc_value() void colvar::dipole_angle::calc_value()
{ {
cvm::atom_pos const g1_pos = group1->center_of_mass(); cvm::atom_pos const g1_pos = group1->center_of_mass();
@ -229,52 +194,35 @@ void colvar::dipole_angle::calc_gradients()
} }
void colvar::dipole_angle::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce) colvar::dihedral::dihedral()
group2->apply_colvar_force(force.real_value);
if (!group3->noforce)
group3->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(dipole_angle)
colvar::dihedral::dihedral(std::string const &conf)
: cvc(conf)
{ {
set_function_type("dihedral"); set_function_type("dihedral");
init_as_periodic_angle(); init_as_periodic_angle();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
enable(f_cvc_com_based); enable(f_cvc_com_based);
}
int colvar::dihedral::init(std::string const &conf)
{
int error_code = cvc::init(conf);
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2"); group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3"); group3 = parse_group(conf, "group3");
group4 = parse_group(conf, "group4"); group4 = parse_group(conf, "group4");
init_total_force_params(conf); error_code |= init_total_force_params(conf);
return error_code;
} }
colvar::dihedral::dihedral(cvm::atom const &a1, colvar::dihedral::dihedral(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3,
cvm::atom const &a2,
cvm::atom const &a3,
cvm::atom const &a4) cvm::atom const &a4)
: dihedral()
{ {
set_function_type("dihedral");
init_as_periodic_angle();
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
b_1site_force = false; b_1site_force = false;
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1)); group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
@ -288,16 +236,6 @@ colvar::dihedral::dihedral(cvm::atom const &a1,
} }
colvar::dihedral::dihedral()
{
set_function_type("dihedral");
init_as_periodic_angle();
enable(f_cvc_periodic);
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
}
void colvar::dihedral::calc_value() void colvar::dihedral::calc_value()
{ {
cvm::atom_pos const g1_pos = group1->center_of_mass(); cvm::atom_pos const g1_pos = group1->center_of_mass();
@ -323,7 +261,7 @@ void colvar::dihedral::calc_value()
cvm::real const sin_phi = n1 * r34 * r23.norm(); cvm::real const sin_phi = n1 * r34 * r23.norm();
x.real_value = (180.0/PI) * cvm::atan2(sin_phi, cos_phi); x.real_value = (180.0/PI) * cvm::atan2(sin_phi, cos_phi);
this->wrap(x); wrap(x);
} }
@ -349,7 +287,7 @@ void colvar::dihedral::calc_gradients()
A *= rA; A *= rA;
cvm::rvector const dcosdA = rA*(cos_phi*A-B); cvm::rvector const dcosdA = rA*(cos_phi*A-B);
cvm::rvector const dcosdB = rB*(cos_phi*B-A); cvm::rvector const dcosdB = rB*(cos_phi*B-A);
rA = 1.0; // rA = 1.0;
cvm::real const K = (1.0/sin_phi) * (180.0/PI); cvm::real const K = (1.0/sin_phi) * (180.0/PI);
@ -363,7 +301,7 @@ void colvar::dihedral::calc_gradients()
C *= rC; C *= rC;
cvm::rvector const dsindC = rC*(sin_phi*C-B); cvm::rvector const dsindC = rC*(sin_phi*C-B);
cvm::rvector const dsindB = rB*(sin_phi*B-C); cvm::rvector const dsindB = rB*(sin_phi*B-C);
rC = 1.0; // rC = 1.0;
cvm::real const K = (-1.0/cos_phi) * (180.0/PI); cvm::real const K = (-1.0/cos_phi) * (180.0/PI);
@ -439,81 +377,22 @@ void colvar::dihedral::calc_Jacobian_derivative()
} }
void colvar::dihedral::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
if (!group3->noforce)
group3->apply_colvar_force(force.real_value);
if (!group4->noforce)
group4->apply_colvar_force(force.real_value);
}
// metrics functions for cvc implementations with a periodicity
cvm::real colvar::dihedral::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::dihedral::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::dihedral::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::dihedral::wrap(colvarvalue &x_unwrapped) const
{
if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
x_unwrapped.real_value -= 360.0;
return;
}
if ((x_unwrapped.real_value - wrap_center) < -180.0) {
x_unwrapped.real_value += 360.0;
return;
}
}
colvar::polar_theta::polar_theta(std::string const &conf)
: cvc(conf)
{
set_function_type("polarTheta");
enable(f_cvc_com_based);
atoms = parse_group(conf, "atoms");
init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
}
colvar::polar_theta::polar_theta() colvar::polar_theta::polar_theta()
{ {
r = theta = phi = 0.0;
set_function_type("polarTheta"); set_function_type("polarTheta");
x.type(colvarvalue::type_scalar); enable(f_cvc_com_based);
init_as_angle();
}
int colvar::polar_theta::init(std::string const &conf)
{
int error_code = cvc::init(conf);
atoms = parse_group(conf, "atoms");
error_code |= init_total_force_params(conf);
return error_code;
} }
@ -540,35 +419,25 @@ void colvar::polar_theta::calc_gradients()
} }
void colvar::polar_theta::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(polar_theta)
colvar::polar_phi::polar_phi(std::string const &conf)
: cvc(conf)
{
set_function_type("polarPhi");
init_as_periodic_angle();
enable(f_cvc_com_based);
atoms = parse_group(conf, "atoms");
init_total_force_params(conf);
}
colvar::polar_phi::polar_phi() colvar::polar_phi::polar_phi()
{ {
r = theta = phi = 0.0;
set_function_type("polarPhi"); set_function_type("polarPhi");
enable(f_cvc_com_based);
init_as_periodic_angle(); init_as_periodic_angle();
} }
int colvar::polar_phi::init(std::string const &conf)
{
int error_code = cvc::init(conf);
atoms = parse_group(conf, "atoms");
error_code |= init_total_force_params(conf);
return error_code;
}
void colvar::polar_phi::calc_value() void colvar::polar_phi::calc_value()
{ {
cvm::rvector pos = atoms->center_of_mass(); cvm::rvector pos = atoms->center_of_mass();
@ -587,55 +456,3 @@ void colvar::polar_phi::calc_gradients()
(180.0/PI) * cvm::cos(phi) / (r*cvm::sin(theta)), (180.0/PI) * cvm::cos(phi) / (r*cvm::sin(theta)),
0.)); 0.));
} }
void colvar::polar_phi::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
// Same as dihedral, for polar_phi
cvm::real colvar::polar_phi::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::polar_phi::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::polar_phi::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::polar_phi::wrap(colvarvalue &x_unwrapped) const
{
if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
x_unwrapped.real_value -= 360.0;
return;
}
if ((x_unwrapped.real_value - wrap_center) < -180.0) {
x_unwrapped.real_value += 360.0;
return;
}
return;
}

View File

@ -1,78 +1,312 @@
#if (__cplusplus >= 201103L) // -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <numeric>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstdlib> #include <iostream>
#include <limits> #include <limits>
#include <numeric>
#include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
#include "colvar_arithmeticpath.h"
colvar::aspathCV::aspathCV(std::string const &conf): CVBasedPath(conf) {
struct ArithmeticPathImpl: public ArithmeticPathCV::ArithmeticPathBase<cvm::real> {
std::vector<std::vector<colvarvalue>> frame_element_distances;
std::vector<std::vector<colvarvalue>> dsdx;
std::vector<std::vector<colvarvalue>> dzdx;
template <typename T>
void updateCartesianDistanceToReferenceFrames(T* obj) {
for (size_t i_frame = 0; i_frame < obj->reference_frames.size(); ++i_frame) {
for (size_t i_atom = 0; i_atom < obj->atoms->size(); ++i_atom) {
frame_element_distances[i_frame][i_atom] = (*(obj->comp_atoms[i_frame]))[i_atom].pos - obj->reference_frames[i_frame][i_atom];
}
}
}
template <typename T>
void updateCVDistanceToReferenceFrames(T* obj) {
for (size_t i_cv = 0; i_cv < obj->cv.size(); ++i_cv) {
obj->cv[i_cv]->calc_value();
}
for (size_t i_frame = 0; i_frame < obj->ref_cv.size(); ++i_frame) {
for (size_t i_cv = 0; i_cv < obj->cv.size(); ++i_cv) {
colvarvalue ref_cv_value(obj->ref_cv[i_frame][i_cv]);
colvarvalue current_cv_value(obj->cv[i_cv]->value());
if (current_cv_value.type() == colvarvalue::type_scalar) {
frame_element_distances[i_frame][i_cv] = 0.5 * obj->cv[i_cv]->dist2_lgrad(obj->cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, obj->cv[i_cv]->sup_np)), ref_cv_value.real_value);
} else {
frame_element_distances[i_frame][i_cv] = 0.5 * obj->cv[i_cv]->dist2_lgrad(obj->cv[i_cv]->sup_coeff * current_cv_value, ref_cv_value);
}
}
}
}
ArithmeticPathImpl(size_t p_num_elements, size_t p_total_frames, cvm::real p_lambda, const std::vector<cvm::real>& p_weights) {
ArithmeticPathCV::ArithmeticPathBase<cvm::real>::initialize(p_num_elements, p_total_frames, p_lambda, p_weights);
frame_element_distances.resize(p_total_frames, std::vector<colvarvalue>(p_num_elements, colvarvalue(colvarvalue::Type::type_notset)));
dsdx.resize(p_total_frames, std::vector<colvarvalue>(p_num_elements, colvarvalue(colvarvalue::Type::type_notset)));
dzdx.resize(p_total_frames, std::vector<colvarvalue>(p_num_elements, colvarvalue(colvarvalue::Type::type_notset)));
}
cvm::real get_lambda() const {return lambda;}
cvm::real compute_s() {
cvm::real s;
computeValue(frame_element_distances, &s, nullptr);
return s;
}
cvm::real compute_z() {
cvm::real z;
computeValue(frame_element_distances, nullptr, &z);
return z;
}
void compute_s_derivatives() {
computeDerivatives<colvarvalue>(frame_element_distances, &dsdx, nullptr);
}
void compute_z_derivatives() {
computeDerivatives<colvarvalue>(frame_element_distances, nullptr, &dzdx);
}
// for debug gradients of implicit sub CVs
template <typename T>
colvarvalue compute_s_analytical_derivative_ij(size_t i, size_t j, cvm::real eps, T* obj) const {
ArithmeticPathImpl tmp_left(*this), tmp_right(*this);
const size_t value_size = frame_element_distances[i][j].size();
colvarvalue result(frame_element_distances[i][j].type());
colvarvalue ref_cv_value(obj->ref_cv[i][j]);
for (size_t k = 0; k < value_size; ++k) {
// get the current CV value
colvarvalue current_cv_value(obj->cv[j]->value());
// save the old values in frame element distance matrices
const auto saved_left = tmp_left.frame_element_distances[i][j][k];
const auto saved_right = tmp_right.frame_element_distances[i][j][k];
// update frame element distance matrices
if (current_cv_value.type() == colvarvalue::type_scalar) {
tmp_left.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * (cvm::pow(current_cv_value.real_value - eps, obj->cv[j]->sup_np)), ref_cv_value.real_value);
tmp_right.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * (cvm::pow(current_cv_value.real_value + eps, obj->cv[j]->sup_np)), ref_cv_value.real_value);
} else {
current_cv_value[k] -= eps;
tmp_left.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * current_cv_value, ref_cv_value);
current_cv_value[k] += eps + eps;
tmp_right.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * current_cv_value, ref_cv_value);
}
const cvm::real s_left = tmp_left.compute_s();
const cvm::real s_right = tmp_right.compute_s();
result[k] = (s_right - s_left) / (2.0 * eps);
tmp_left.frame_element_distances[i][j][k] = saved_left;
tmp_right.frame_element_distances[i][j][k] = saved_right;
}
return result;
}
template <typename T>
colvarvalue compute_z_analytical_derivative_ij(size_t i, size_t j, cvm::real eps, T* obj) const {
ArithmeticPathImpl tmp_left(*this), tmp_right(*this);
const size_t value_size = frame_element_distances[i][j].size();
colvarvalue result(frame_element_distances[i][j].type());
colvarvalue ref_cv_value(obj->ref_cv[i][j]);
for (size_t k = 0; k < value_size; ++k) {
// get the current CV value
colvarvalue current_cv_value(obj->cv[j]->value());
// save the old values in frame element distance matrices
const auto saved_left = tmp_left.frame_element_distances[i][j][k];
const auto saved_right = tmp_right.frame_element_distances[i][j][k];
// update frame element distance matrices
if (current_cv_value.type() == colvarvalue::type_scalar) {
tmp_left.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * (cvm::pow(current_cv_value.real_value - eps, obj->cv[j]->sup_np)), ref_cv_value.real_value);
tmp_right.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * (cvm::pow(current_cv_value.real_value + eps, obj->cv[j]->sup_np)), ref_cv_value.real_value);
} else {
current_cv_value[k] -= eps;
tmp_left.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * current_cv_value, ref_cv_value);
current_cv_value[k] += eps + eps;
tmp_right.frame_element_distances[i][j] = 0.5 * obj->cv[j]->dist2_lgrad(obj->cv[j]->sup_coeff * current_cv_value, ref_cv_value);
}
const cvm::real z_left = tmp_left.compute_z();
const cvm::real z_right = tmp_right.compute_z();
result[k] = (z_right - z_left) / (2.0 * eps);
tmp_left.frame_element_distances[i][j][k] = saved_left;
tmp_right.frame_element_distances[i][j][k] = saved_right;
}
return result;
}
};
colvar::aspath::aspath()
{
set_function_type("aspath");
x.type(colvarvalue::type_scalar);
}
int colvar::aspath::init(std::string const &conf)
{
int error_code = CartesianBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
cvm::real p_lambda;
get_keyval(conf, "lambda", p_lambda, -1.0);
const size_t num_atoms = atoms->size();
std::vector<cvm::real> p_weights(num_atoms, std::sqrt(1.0 / num_atoms));
// ArithmeticPathCV::ArithmeticPathBase<cvm::atom_pos, cvm::real, ArithmeticPathCV::path_sz::S>::initialize(num_atoms, total_reference_frames, p_lambda, reference_frames[0], p_weights);
if (impl_) impl_.reset();
impl_ = std::unique_ptr<ArithmeticPathImpl>(new ArithmeticPathImpl(num_atoms, total_reference_frames, p_lambda, p_weights));
cvm::log(std::string("Lambda is ") + cvm::to_str(impl_->get_lambda()) + std::string("\n"));
return error_code;
}
colvar::aspath::~aspath() {}
void colvar::aspath::calc_value() {
if (impl_->get_lambda() < 0) {
// this implies that the user may not set a valid lambda value
// so recompute it by the suggested value in Parrinello's paper
cvm::log("A non-positive value of lambda is detected, which implies that it may not set in the configuration.\n");
cvm::log("This component (aspath) will recompute a value for lambda following the suggestion in the origin paper.\n");
std::vector<cvm::real> rmsd_between_refs(total_reference_frames - 1, 0.0);
computeDistanceBetweenReferenceFrames(rmsd_between_refs);
impl_->reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(impl_->get_lambda()));
}
impl_->updateCartesianDistanceToReferenceFrames(this);
x = impl_->compute_s();
}
void colvar::aspath::calc_gradients() {
impl_->compute_s_derivatives();
for (size_t i_frame = 0; i_frame < reference_frames.size(); ++i_frame) {
for (size_t i_atom = 0; i_atom < atoms->size(); ++i_atom) {
(*(comp_atoms[i_frame]))[i_atom].grad += impl_->dsdx[i_frame][i_atom];
}
}
}
void colvar::aspath::apply_force(colvarvalue const &force) {
cvm::real const &F = force.real_value;
for (size_t i_frame = 0; i_frame < reference_frames.size(); ++i_frame) {
(*(comp_atoms[i_frame])).apply_colvar_force(F);
}
}
colvar::azpath::azpath()
{
set_function_type("azpath");
x.type(colvarvalue::type_scalar);
}
int colvar::azpath::init(std::string const &conf)
{
int error_code = CartesianBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
x.type(colvarvalue::type_scalar);
cvm::real p_lambda;
get_keyval(conf, "lambda", p_lambda, -1.0);
const size_t num_atoms = atoms->size();
std::vector<cvm::real> p_weights(num_atoms, std::sqrt(1.0 / num_atoms));
if (impl_) impl_.reset();
impl_ = std::unique_ptr<ArithmeticPathImpl>(new ArithmeticPathImpl(num_atoms, total_reference_frames, p_lambda, p_weights));
cvm::log(std::string("Lambda is ") + cvm::to_str(impl_->get_lambda()) + std::string("\n"));
return error_code;
}
colvar::azpath::~azpath() {}
void colvar::azpath::calc_value() {
if (impl_->get_lambda() < 0) {
// this implies that the user may not set a valid lambda value
// so recompute it by the suggested value in Parrinello's paper
cvm::log("A non-positive value of lambda is detected, which implies that it may not set in the configuration.\n");
cvm::log("This component (azpath) will recompute a value for lambda following the suggestion in the origin paper.\n");
std::vector<cvm::real> rmsd_between_refs(total_reference_frames - 1, 0.0);
computeDistanceBetweenReferenceFrames(rmsd_between_refs);
impl_->reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(impl_->get_lambda()));
}
impl_->updateCartesianDistanceToReferenceFrames(this);
x = impl_->compute_z();
}
void colvar::azpath::calc_gradients() {
impl_->compute_z_derivatives();
for (size_t i_frame = 0; i_frame < reference_frames.size(); ++i_frame) {
for (size_t i_atom = 0; i_atom < atoms->size(); ++i_atom) {
(*(comp_atoms[i_frame]))[i_atom].grad += impl_->dzdx[i_frame][i_atom];
}
}
}
void colvar::azpath::apply_force(colvarvalue const &force) {
cvm::real const &F = force.real_value;
for (size_t i_frame = 0; i_frame < reference_frames.size(); ++i_frame) {
(*(comp_atoms[i_frame])).apply_colvar_force(F);
}
}
colvar::aspathCV::aspathCV()
{
set_function_type("aspathCV"); set_function_type("aspathCV");
x.type(colvarvalue::type_scalar);
}
int colvar::aspathCV::init(std::string const &conf)
{
int error_code = CVBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
std::vector<cvm::real> p_weights(cv.size(), 1.0); std::vector<cvm::real> p_weights(cv.size(), 1.0);
get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0)); get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0));
x.type(colvarvalue::type_scalar);
use_explicit_gradients = true; use_explicit_gradients = true;
cvm::real p_lambda; cvm::real p_lambda;
get_keyval(conf, "lambda", p_lambda, -1.0); get_keyval(conf, "lambda", p_lambda, -1.0);
ArithmeticPathCV::ArithmeticPathBase<colvarvalue, cvm::real, ArithmeticPathCV::path_sz::S>::initialize(cv.size(), total_reference_frames, p_lambda, ref_cv[0], p_weights); if (impl_) impl_.reset();
cvm::log(std::string("Lambda is ") + cvm::to_str(lambda) + std::string("\n")); impl_ = std::unique_ptr<ArithmeticPathImpl>(new ArithmeticPathImpl(cv.size(), total_reference_frames, p_lambda, p_weights));
cvm::log(std::string("Lambda is ") + cvm::to_str(impl_->get_lambda()) + std::string("\n"));
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) { if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
use_explicit_gradients = false; use_explicit_gradients = false;
} }
cvm::log(std::string("The weight of CV ") + cvm::to_str(i_cv) + std::string(" is ") + cvm::to_str(weights[i_cv]) + std::string("\n")); cvm::log(std::string("The weight of CV ") + cvm::to_str(i_cv) + std::string(" is ") + cvm::to_str(p_weights[i_cv]) + std::string("\n"));
} }
return error_code;
} }
void colvar::aspathCV::updateDistanceToReferenceFrames() { colvar::aspathCV::~aspathCV() {}
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_value();
}
for (size_t i_frame = 0; i_frame < ref_cv.size(); ++i_frame) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
colvarvalue ref_cv_value(ref_cv[i_frame][i_cv]);
colvarvalue current_cv_value(cv[i_cv]->value());
if (current_cv_value.type() == colvarvalue::type_scalar) {
frame_element_distances[i_frame][i_cv] = 0.5 * cv[i_cv]->dist2_lgrad(cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, cv[i_cv]->sup_np)), ref_cv_value.real_value);
} else {
frame_element_distances[i_frame][i_cv] = 0.5 * cv[i_cv]->dist2_lgrad(cv[i_cv]->sup_coeff * current_cv_value, ref_cv_value);
}
}
}
}
void colvar::aspathCV::calc_value() { void colvar::aspathCV::calc_value() {
if (lambda < 0) { if (impl_->get_lambda() < 0) {
// this implies that the user may not set a valid lambda value // this implies that the user may not set a valid lambda value
// so recompute it by the suggested value in Parrinello's paper // so recompute it by the suggested value in Parrinello's paper
cvm::log("A non-positive value of lambda is detected, which implies that it may not set in the configuration.\n"); cvm::log("A non-positive value of lambda is detected, which implies that it may not set in the configuration.\n");
cvm::log("This component (aspathCV) will recompute a value for lambda following the suggestion in the origin paper.\n"); cvm::log("This component (aspathCV) will recompute a value for lambda following the suggestion in the origin paper.\n");
std::vector<cvm::real> rmsd_between_refs(total_reference_frames - 1, 0.0); std::vector<cvm::real> rmsd_between_refs(total_reference_frames - 1, 0.0);
computeDistanceBetweenReferenceFrames(rmsd_between_refs); computeDistanceBetweenReferenceFrames(rmsd_between_refs);
reComputeLambda(rmsd_between_refs); impl_->reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(lambda)); cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(impl_->get_lambda()));
} }
computeValue(); impl_->updateCVDistanceToReferenceFrames(this);
x = s; x = impl_->compute_s();
} }
void colvar::aspathCV::calc_gradients() { void colvar::aspathCV::calc_gradients() {
computeDerivatives(); impl_->compute_s_derivatives();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients(); cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) { if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
// compute the gradient (grad) with respect to the i-th CV
colvarvalue grad(cv[i_cv]->value().type());
// sum up derivatives with respect to all frames
for (size_t m_frame = 0; m_frame < impl_->dsdx.size(); ++m_frame) {
// dsdx is the derivative of s with respect to the m-th frame
grad += impl_->dsdx[m_frame][i_cv];
}
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) { for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) { for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) {
(*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = dsdx[i_cv][j_elem] * factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad; (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = grad[j_elem] * factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad;
} }
} }
} }
@ -88,97 +322,137 @@ void colvar::aspathCV::apply_force(colvarvalue const &force) {
} }
} else { } else {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
colvarvalue cv_force = dsdx[i_cv] * force.real_value * factor_polynomial; // compute the gradient (grad) with respect to the i-th CV
cv[i_cv]->apply_force(cv_force); colvarvalue grad(cv[i_cv]->value().type());
} for (size_t m_frame = 0; m_frame < impl_->dsdx.size(); ++m_frame) {
} // dsdx is the derivative of s with respect to the m-th frame
} grad += impl_->dsdx[m_frame][i_cv];
}
colvar::aspathCV::~aspathCV() {} grad *= factor_polynomial;
cv[i_cv]->apply_force(force.real_value * grad);
colvar::azpathCV::azpathCV(std::string const &conf): CVBasedPath(conf) { // try my best to debug gradients even if the sub-CVs do not have explicit gradients
set_function_type("azpathCV"); if (is_enabled(f_cvc_debug_gradient)) {
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log("Debugging gradients for " + description +
std::vector<cvm::real> p_weights(cv.size(), 1.0); " with respect to sub-CV " + cv[i_cv]->description +
get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0)); ", which has no explicit gradient with respect to its own input(s)");
x.type(colvarvalue::type_scalar); colvarvalue analytical_grad(cv[i_cv]->value().type());
use_explicit_gradients = true; for (size_t m_frame = 0; m_frame < impl_->dsdx.size(); ++m_frame) {
cvm::real p_lambda; analytical_grad += impl_->compute_s_analytical_derivative_ij(
get_keyval(conf, "lambda", p_lambda, -1.0); m_frame, i_cv, cvm::debug_gradients_step_size, this);
ArithmeticPathCV::ArithmeticPathBase<colvarvalue, cvm::real, ArithmeticPathCV::path_sz::Z>::initialize(cv.size(), total_reference_frames, p_lambda, ref_cv[0], p_weights); }
cvm::log(std::string("Lambda is ") + cvm::to_str(lambda) + std::string("\n")); cvm::log("dx(actual) = "+cvm::to_str(analytical_grad, 21, 14)+"\n");
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { cvm::log("dx(interp) = "+cvm::to_str(grad, 21, 14)+"\n");
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) { cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+
use_explicit_gradients = false; cvm::to_str((analytical_grad - grad).norm() /
} (analytical_grad).norm(), 12, 5)+"\n");
cvm::log(std::string("The weight of CV ") + cvm::to_str(i_cv) + std::string(" is ") + cvm::to_str(weights[i_cv]) + std::string("\n"));
}
}
void colvar::azpathCV::updateDistanceToReferenceFrames() {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_value();
}
for (size_t i_frame = 0; i_frame < ref_cv.size(); ++i_frame) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
colvarvalue ref_cv_value(ref_cv[i_frame][i_cv]);
colvarvalue current_cv_value(cv[i_cv]->value());
if (current_cv_value.type() == colvarvalue::type_scalar) {
frame_element_distances[i_frame][i_cv] = 0.5 * cv[i_cv]->dist2_lgrad(cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, cv[i_cv]->sup_np)), ref_cv_value.real_value);
} else {
frame_element_distances[i_frame][i_cv] = 0.5 * cv[i_cv]->dist2_lgrad(cv[i_cv]->sup_coeff * current_cv_value, ref_cv_value);
} }
} }
} }
} }
colvar::azpathCV::azpathCV()
{
set_function_type("azpathCV");
x.type(colvarvalue::type_scalar);
}
int colvar::azpathCV::init(std::string const &conf)
{
int error_code = CVBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
std::vector<cvm::real> p_weights(cv.size(), 1.0);
get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0));
use_explicit_gradients = true;
cvm::real p_lambda;
get_keyval(conf, "lambda", p_lambda, -1.0);
if (impl_) impl_.reset();
impl_ = std::unique_ptr<ArithmeticPathImpl>(new ArithmeticPathImpl(cv.size(), total_reference_frames, p_lambda, p_weights));
cvm::log(std::string("Lambda is ") + cvm::to_str(impl_->get_lambda()) + std::string("\n"));
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
use_explicit_gradients = false;
}
cvm::log(std::string("The weight of CV ") + cvm::to_str(i_cv) + std::string(" is ") + cvm::to_str(p_weights[i_cv]) + std::string("\n"));
}
return error_code;
}
void colvar::azpathCV::calc_value() { void colvar::azpathCV::calc_value() {
if (lambda < 0) { if (impl_->get_lambda() < 0) {
// this implies that the user may not set a valid lambda value // this implies that the user may not set a valid lambda value
// so recompute it by the suggested value in Parrinello's paper // so recompute it by the suggested value in Parrinello's paper
cvm::log("A non-positive value of lambda is detected, which implies that it may not set in the configuration.\n"); cvm::log("A non-positive value of lambda is detected, which implies that it may not set in the configuration.\n");
cvm::log("This component (azpathCV) will recompute a value for lambda following the suggestion in the origin paper.\n"); cvm::log("This component (azpathCV) will recompute a value for lambda following the suggestion in the origin paper.\n");
std::vector<cvm::real> rmsd_between_refs(total_reference_frames - 1, 0.0); std::vector<cvm::real> rmsd_between_refs(total_reference_frames - 1, 0.0);
computeDistanceBetweenReferenceFrames(rmsd_between_refs); computeDistanceBetweenReferenceFrames(rmsd_between_refs);
reComputeLambda(rmsd_between_refs); impl_->reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(lambda)); cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(impl_->get_lambda()));
} }
computeValue(); impl_->updateCVDistanceToReferenceFrames(this);
x = z; x = impl_->compute_z();
} }
void colvar::azpathCV::calc_gradients() { void colvar::azpathCV::calc_gradients() {
computeDerivatives(); impl_->compute_z_derivatives();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients(); cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) { if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
// compute the gradient (grad) with respect to the i-th CV
colvarvalue grad(cv[i_cv]->value().type());
// sum up derivatives with respect to all frames
for (size_t m_frame = 0; m_frame < impl_->dzdx.size(); ++m_frame) {
// dzdx is the derivative of z with respect to the m-th frame
grad += impl_->dzdx[m_frame][i_cv];
}
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) { for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) { for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) {
(*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = dzdx[i_cv][j_elem] * factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad; (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = grad[j_elem] * factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad;
} }
} }
} }
} }
} }
} }
void colvar::azpathCV::apply_force(colvarvalue const &force) { void colvar::azpathCV::apply_force(colvarvalue const &force) {
// the PCV component itself is a scalar, so force should be scalar
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) { if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value); (cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
} }
} else { } else {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
const colvarvalue cv_force = dzdx[i_cv] * force.real_value * factor_polynomial; // compute the gradient (grad) with respect to the i-th CV
cv[i_cv]->apply_force(cv_force); colvarvalue grad(cv[i_cv]->value().type());
for (size_t m_frame = 0; m_frame < impl_->dzdx.size(); ++m_frame) {
// dzdx is the derivative of z with respect to the m-th frame
grad += impl_->dzdx[m_frame][i_cv];
}
grad *= factor_polynomial;
cv[i_cv]->apply_force(force.real_value * grad);
// try my best to debug gradients even if the sub-CVs do not have explicit gradients
if (is_enabled(f_cvc_debug_gradient)) {
cvm::log("Debugging gradients for " + description +
" with respect to sub-CV " + cv[i_cv]->description +
", which has no explicit gradient with respect to its own input(s)");
colvarvalue analytical_grad(cv[i_cv]->value().type());
for (size_t m_frame = 0; m_frame < impl_->dzdx.size(); ++m_frame) {
analytical_grad += impl_->compute_z_analytical_derivative_ij(
m_frame, i_cv, cvm::debug_gradients_step_size, this);
}
cvm::log("dx(actual) = "+cvm::to_str(analytical_grad, 21, 14)+"\n");
cvm::log("dx(interp) = "+cvm::to_str(grad, 21, 14)+"\n");
cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+
cvm::to_str((analytical_grad - grad).norm() /
(analytical_grad).norm(), 12, 5)+"\n");
}
} }
} }
} }
colvar::azpathCV::~azpathCV() {} colvar::azpathCV::~azpathCV() {}
#endif

View File

@ -1,4 +1,4 @@
#if (__cplusplus >= 201103L) // -*- c++ -*-
// This file is part of the Collective Variables module (Colvars). // This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at: // The original version of Colvars and its updates are located at:
@ -9,14 +9,26 @@
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::linearCombination::linearCombination(std::string const &conf): cvc(conf) {
colvar::linearCombination::linearCombination()
{
set_function_type("linearCombination");
}
int colvar::linearCombination::init(std::string const &conf)
{
int error_code = cvc::init(conf);
if (error_code != COLVARS_OK) return error_code;
// Lookup all available sub-cvcs // Lookup all available sub-cvcs
for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) { for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) {
if (key_lookup(conf, it_cv_map->first.c_str())) { if (key_lookup(conf, it_cv_map->first.c_str())) {
std::vector<std::string> sub_cvc_confs; std::vector<std::string> sub_cvc_confs;
get_key_string_multi_value(conf, it_cv_map->first.c_str(), sub_cvc_confs); get_key_string_multi_value(conf, it_cv_map->first.c_str(), sub_cvc_confs);
for (auto it_sub_cvc_conf = sub_cvc_confs.begin(); it_sub_cvc_conf != sub_cvc_confs.end(); ++it_sub_cvc_conf) { for (auto it_sub_cvc_conf = sub_cvc_confs.begin(); it_sub_cvc_conf != sub_cvc_confs.end(); ++it_sub_cvc_conf) {
cv.push_back((it_cv_map->second)(*(it_sub_cvc_conf))); cv.push_back((it_cv_map->second)());
cv.back()->init(*(it_sub_cvc_conf));
} }
} }
} }
@ -29,26 +41,11 @@ colvar::linearCombination::linearCombination(std::string const &conf): cvc(conf)
} }
// Show useful error messages and prevent crashes if no sub CVC is found // Show useful error messages and prevent crashes if no sub CVC is found
if (cv.size() == 0) { if (cv.size() == 0) {
cvm::error("Error: the CV " + name + return cvm::error("Error: the CV " + name + " expects one or more nesting components.\n",
" expects one or more nesting components.\n"); COLVARS_INPUT_ERROR);
return;
} else { } else {
// TODO: Maybe we can add an option to allow mixing scalar and vector types,
// but that's a bit complicated so we just require a consistent type
// of nesting CVs.
x.type(cv[0]->value()); x.type(cv[0]->value());
x.reset(); x.reset();
for (size_t i_cv = 1; i_cv < cv.size(); ++i_cv) {
const auto type_i = cv[i_cv]->value().type();
if (type_i != x.type()) {
cvm::error("Error: the type of sub-CVC " + cv[i_cv]->name +
" is " + colvarvalue::type_desc(type_i) + ", which is "
"different to the type of the first sub-CVC. Currently "
"only sub-CVCs of the same type are supported to be "
"nested.\n");
return;
}
}
} }
use_explicit_gradients = true; use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
@ -59,6 +56,7 @@ colvar::linearCombination::linearCombination(std::string const &conf): cvc(conf)
if (!use_explicit_gradients) { if (!use_explicit_gradients) {
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
} }
return error_code;
} }
cvm::real colvar::linearCombination::getPolynomialFactorOfCVGradient(size_t i_cv) const { cvm::real colvar::linearCombination::getPolynomialFactorOfCVGradient(size_t i_cv) const {
@ -138,8 +136,42 @@ void colvar::linearCombination::apply_force(colvarvalue const &force) {
} }
} }
colvar::customColvar::customColvar(std::string const &conf): linearCombination(conf) {
use_custom_function = false; cvm::real colvar::linearCombination::dist2(colvarvalue const &x1, colvarvalue const &x2) const
{
return x1.dist2(x2);
}
colvarvalue colvar::linearCombination::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x1.dist2_grad(x2);
}
colvarvalue colvar::linearCombination::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x2.dist2_grad(x1);
}
void colvar::linearCombination::wrap(colvarvalue & /* x_unwrapped */) const {}
colvar::customColvar::customColvar()
{
set_function_type("customColvar");
}
int colvar::customColvar::init(std::string const &conf)
{
int error_code = linearCombination::init(conf);
if (error_code != COLVARS_OK) return error_code;
// code swipe from colvar::init_custom_function // code swipe from colvar::init_custom_function
std::string expr_in, expr; std::string expr_in, expr;
size_t pos = 0; // current position in config string size_t pos = 0; // current position in config string
@ -160,7 +192,7 @@ colvar::customColvar::customColvar(std::string const &conf): linearCombination(c
pexpr = Lepton::Parser::parse(expr); pexpr = Lepton::Parser::parse(expr);
pexprs.push_back(pexpr); pexprs.push_back(pexpr);
} catch (...) { } catch (...) {
cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR); return cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
} }
try { try {
value_evaluators.push_back(new Lepton::CompiledExpression(pexpr.createCompiledExpression())); value_evaluators.push_back(new Lepton::CompiledExpression(pexpr.createCompiledExpression()));
@ -178,7 +210,7 @@ colvar::customColvar::customColvar(std::string const &conf): linearCombination(c
} }
} }
} catch (...) { } catch (...) {
cvm::error("Error compiling expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR); return cvm::error("Error compiling expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
} }
} while (key_lookup(conf, "customFunction", &expr_in, &pos)); } while (key_lookup(conf, "customFunction", &expr_in, &pos));
// Now define derivative with respect to each scalar sub-component // Now define derivative with respect to each scalar sub-component
@ -203,7 +235,7 @@ colvar::customColvar::customColvar(std::string const &conf): linearCombination(c
} }
} }
if (value_evaluators.size() == 0) { if (value_evaluators.size() == 0) {
cvm::error("Error: no custom function defined.\n", COLVARS_INPUT_ERROR); return cvm::error("Error: no custom function defined.\n", COLVARS_INPUT_ERROR);
} }
if (value_evaluators.size() != 1) { if (value_evaluators.size() != 1) {
x.type(colvarvalue::type_vector); x.type(colvarvalue::type_vector);
@ -211,14 +243,17 @@ colvar::customColvar::customColvar(std::string const &conf): linearCombination(c
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
} }
#else #else
cvm::error("customFunction requires the Lepton library, but it is not enabled during compilation.\n" return cvm::error(
"Please refer to the Compilation Notes section of the Colvars manual for more information.\n", "customFunction requires the Lepton library, but it is not enabled during compilation.\n"
COLVARS_INPUT_ERROR); "Please refer to the Compilation Notes section of the Colvars manual for more "
"information.\n",
COLVARS_NOT_IMPLEMENTED);
#endif #endif
} else { } else {
cvm::log("Warning: no customFunction specified.\n"); cvm::log("Warning: no customFunction specified.\n");
cvm::log("Warning: use linear combination instead.\n"); cvm::log("Warning: use linear combination instead.\n");
} }
return error_code;
} }
colvar::customColvar::~customColvar() { colvar::customColvar::~customColvar() {
@ -317,7 +352,8 @@ void colvar::customColvar::apply_force(colvarvalue const &force) {
} }
} else { } else {
const colvarvalue& current_cv_value = cv[i_cv]->value(); const colvarvalue& current_cv_value = cv[i_cv]->value();
colvarvalue cv_force(current_cv_value.type()); colvarvalue cv_force(current_cv_value);
cv_force.reset();
const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < current_cv_value.size(); ++j_elem) { for (size_t j_elem = 0; j_elem < current_cv_value.size(); ++j_elem) {
for (size_t c = 0; c < x.size(); ++c) { for (size_t c = 0; c < x.size(); ++c) {
@ -340,5 +376,3 @@ void colvar::customColvar::apply_force(colvarvalue const &force) {
#endif #endif
} }
} }
#endif // __cplusplus >= 201103L

View File

@ -8,7 +8,6 @@
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarparse.h"
#include "colvaratoms.h" #include "colvaratoms.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvar.h" #include "colvar.h"
@ -90,48 +89,47 @@ cvm::real colvar::coordnum::switching_function(cvm::real const &r0,
} }
colvar::coordnum::coordnum(std::string const &conf) colvar::coordnum::coordnum()
: cvc(conf), b_anisotropic(false), pairlist(NULL)
{ {
set_function_type("coordNum"); set_function_type("coordNum");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
r0 = proxy->angstrom_to_internal(4.0);
r0_vec = cvm::rvector(proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0));
}
int colvar::coordnum::init(std::string const &conf)
{
int error_code = cvc::init(conf);
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2"); group2 = parse_group(conf, "group2");
if (group1 == NULL || group2 == NULL) { if (!group1 || !group2) {
cvm::error("Error: failed to initialize atom groups.\n", return error_code | COLVARS_INPUT_ERROR;
COLVARS_INPUT_ERROR);
return;
} }
if (int atom_number = cvm::atom_group::overlap(*group1, *group2)) { if (int atom_number = cvm::atom_group::overlap(*group1, *group2)) {
cvm::error("Error: group1 and group2 share a common atom (number: " + error_code |= cvm::error(
cvm::to_str(atom_number) + ")\n", COLVARS_INPUT_ERROR); "Error: group1 and group2 share a common atom (number: " + cvm::to_str(atom_number) + ")\n",
return; COLVARS_INPUT_ERROR);
} }
if (group1->b_dummy) { if (group1->b_dummy) {
cvm::error("Error: only group2 is allowed to be a dummy atom\n", error_code |=
COLVARS_INPUT_ERROR); cvm::error("Error: only group2 is allowed to be a dummy atom\n", COLVARS_INPUT_ERROR);
return;
} }
bool const b_isotropic = get_keyval(conf, "cutoff", r0, bool const b_isotropic = get_keyval(conf, "cutoff", r0, r0);
cvm::real(proxy->angstrom_to_internal(4.0)));
if (get_keyval(conf, "cutoff3", r0_vec, if (get_keyval(conf, "cutoff3", r0_vec, r0_vec)) {
cvm::rvector(proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0)))) {
if (b_isotropic) { if (b_isotropic) {
cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" " error_code |= cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" "
"at the same time.\n", "at the same time.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
return;
} }
b_anisotropic = true; b_anisotropic = true;
@ -141,17 +139,17 @@ colvar::coordnum::coordnum(std::string const &conf)
if (r0_vec.z < 0.0) r0_vec.z *= -1.0; if (r0_vec.z < 0.0) r0_vec.z *= -1.0;
} }
get_keyval(conf, "expNumer", en, 6); get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, 12); get_keyval(conf, "expDenom", ed, ed);
if ( (en%2) || (ed%2) ) { if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", error_code |= cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ( (en <= 0) || (ed <= 0) ) {
cvm::error("Error: negative exponent(s) provided.\n", error_code |= cvm::error("Error: negative exponent(s) provided.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (!is_enabled(f_cvc_pbc_minimum_image)) { if (!is_enabled(f_cvc_pbc_minimum_image)) {
@ -160,14 +158,14 @@ colvar::coordnum::coordnum(std::string const &conf)
get_keyval(conf, "group2CenterOnly", b_group2_center_only, group2->b_dummy); get_keyval(conf, "group2CenterOnly", b_group2_center_only, group2->b_dummy);
get_keyval(conf, "tolerance", tolerance, 0.0); get_keyval(conf, "tolerance", tolerance, tolerance);
if (tolerance > 0) { if (tolerance > 0) {
cvm::main()->cite_feature("coordNum pairlist"); cvm::main()->cite_feature("coordNum pairlist");
get_keyval(conf, "pairListFrequency", pairlist_freq, 100); get_keyval(conf, "pairListFrequency", pairlist_freq, pairlist_freq);
if ( ! (pairlist_freq > 0) ) { if ( ! (pairlist_freq > 0) ) {
cvm::error("Error: non-positive pairlistfrequency provided.\n", return cvm::error("Error: non-positive pairlistfrequency provided.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
return; // and do not allocate the pairlists below // return and do not allocate the pairlists below
} }
if (b_group2_center_only) { if (b_group2_center_only) {
pairlist = new bool[group1->size()]; pairlist = new bool[group1->size()];
@ -181,12 +179,14 @@ colvar::coordnum::coordnum(std::string const &conf)
static_cast<cvm::real>(group1->size()) : static_cast<cvm::real>(group1->size()) :
static_cast<cvm::real>(group1->size() * static_cast<cvm::real>(group1->size() *
group2->size())); group2->size()));
return error_code;
} }
colvar::coordnum::~coordnum() colvar::coordnum::~coordnum()
{ {
if (pairlist != NULL) { if (pairlist) {
delete [] pairlist; delete [] pairlist;
} }
} }
@ -285,25 +285,23 @@ void colvar::coordnum::calc_gradients()
} }
void colvar::coordnum::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(coordnum)
// h_bond member functions // h_bond member functions
colvar::h_bond::h_bond(std::string const &conf) colvar::h_bond::h_bond()
: cvc(conf)
{ {
colvarproxy *proxy = cvm::main()->proxy;
r0 = proxy->angstrom_to_internal(3.3);
set_function_type("hBond");
x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0);
}
int colvar::h_bond::init(std::string const &conf)
{
int error_code = cvc::init(conf);
if (cvm::debug()) if (cvm::debug())
cvm::log("Initializing h_bond object.\n"); cvm::log("Initializing h_bond object.\n");
@ -311,15 +309,12 @@ colvar::h_bond::h_bond(std::string const &conf)
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
colvarproxy *proxy = cvm::main()->proxy;
int a_num = -1, d_num = -1; int a_num = -1, d_num = -1;
get_keyval(conf, "acceptor", a_num, a_num); get_keyval(conf, "acceptor", a_num, a_num);
get_keyval(conf, "donor", d_num, a_num); get_keyval(conf, "donor", d_num, a_num);
if ( (a_num == -1) || (d_num == -1) ) { if ( (a_num == -1) || (d_num == -1) ) {
cvm::error("Error: either acceptor or donor undefined.\n"); error_code |= cvm::error("Error: either acceptor or donor undefined.\n", COLVARS_INPUT_ERROR);
return;
} }
cvm::atom acceptor = cvm::atom(a_num); cvm::atom acceptor = cvm::atom(a_num);
@ -328,34 +323,34 @@ colvar::h_bond::h_bond(std::string const &conf)
atom_groups[0]->add_atom(acceptor); atom_groups[0]->add_atom(acceptor);
atom_groups[0]->add_atom(donor); atom_groups[0]->add_atom(donor);
get_keyval(conf, "cutoff", r0, proxy->angstrom_to_internal(3.3)); get_keyval(conf, "cutoff", r0, r0);
get_keyval(conf, "expNumer", en, 6); get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, 8); get_keyval(conf, "expDenom", ed, ed);
if ( (en%2) || (ed%2) ) { if ((en % 2) || (ed % 2)) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", error_code |= cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ((en <= 0) || (ed <= 0)) {
cvm::error("Error: negative exponent(s) provided.\n", error_code |= cvm::error("Error: negative exponent(s) provided.\n", COLVARS_INPUT_ERROR);
COLVARS_INPUT_ERROR);
} }
if (cvm::debug()) if (cvm::debug())
cvm::log("Done initializing h_bond object.\n"); cvm::log("Done initializing h_bond object.\n");
return error_code;
} }
colvar::h_bond::h_bond(cvm::atom const &acceptor, colvar::h_bond::h_bond(cvm::atom const &acceptor,
cvm::atom const &donor, cvm::atom const &donor,
cvm::real r0_i, int en_i, int ed_i) cvm::real r0_i, int en_i, int ed_i)
: r0(r0_i), en(en_i), ed(ed_i) : h_bond()
{ {
set_function_type("hBond"); r0 = r0_i;
x.type(colvarvalue::type_scalar); en = en_i;
init_scalar_boundaries(0.0, 1.0); ed = ed_i;
register_atom_group(new cvm::atom_group); register_atom_group(new cvm::atom_group);
atom_groups[0]->add_atom(acceptor); atom_groups[0]->add_atom(acceptor);
atom_groups[0]->add_atom(donor); atom_groups[0]->add_atom(donor);
@ -385,64 +380,63 @@ void colvar::h_bond::calc_gradients()
} }
void colvar::h_bond::apply_force(colvarvalue const &force)
{
(atom_groups[0])->apply_colvar_force(force);
}
colvar::selfcoordnum::selfcoordnum()
simple_scalar_dist_functions(h_bond)
colvar::selfcoordnum::selfcoordnum(std::string const &conf)
: cvc(conf), pairlist(NULL)
{ {
set_function_type("selfCoordNum"); set_function_type("selfCoordNum");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
r0 = cvm::main()->proxy->angstrom_to_internal(4.0);
}
colvarproxy *proxy = cvm::main()->proxy;
int colvar::selfcoordnum::init(std::string const &conf)
{
int error_code = cvc::init(conf);
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
get_keyval(conf, "cutoff", r0, cvm::real(proxy->angstrom_to_internal(4.0))); if (!group1 || group1->size() == 0) {
get_keyval(conf, "expNumer", en, 6); return error_code | COLVARS_INPUT_ERROR;
get_keyval(conf, "expDenom", ed, 12);
if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { get_keyval(conf, "cutoff", r0, r0);
cvm::error("Error: negative exponent(s) provided.\n", get_keyval(conf, "expNumer", en, en);
COLVARS_INPUT_ERROR); get_keyval(conf, "expDenom", ed, ed);
if ((en % 2) || (ed % 2)) {
error_code |= cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
COLVARS_INPUT_ERROR);
}
if ((en <= 0) || (ed <= 0)) {
error_code |= cvm::error("Error: negative exponent(s) provided.\n", COLVARS_INPUT_ERROR);
} }
if (!is_enabled(f_cvc_pbc_minimum_image)) { if (!is_enabled(f_cvc_pbc_minimum_image)) {
cvm::log("Warning: only minimum-image distances are used by this variable.\n"); cvm::log("Warning: only minimum-image distances are used by this variable.\n");
} }
get_keyval(conf, "tolerance", tolerance, 0.0); get_keyval(conf, "tolerance", tolerance, tolerance);
if (tolerance > 0) { if (tolerance > 0) {
get_keyval(conf, "pairListFrequency", pairlist_freq, 100); get_keyval(conf, "pairListFrequency", pairlist_freq, pairlist_freq);
if ( ! (pairlist_freq > 0) ) { if ( ! (pairlist_freq > 0) ) {
cvm::error("Error: non-positive pairlistfrequency provided.\n", error_code |= cvm::error("Error: non-positive pairlistfrequency provided.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
return;
} }
pairlist = new bool[(group1->size()-1) * (group1->size()-1)]; pairlist = new bool[(group1->size()-1) * (group1->size()-1)];
} }
init_scalar_boundaries(0.0, static_cast<cvm::real>((group1->size()-1) * init_scalar_boundaries(0.0, static_cast<cvm::real>((group1->size()-1) *
(group1->size()-1))); (group1->size()-1)));
return error_code;
} }
colvar::selfcoordnum::~selfcoordnum() colvar::selfcoordnum::~selfcoordnum()
{ {
if (pairlist != NULL) { if (pairlist) {
delete [] pairlist; delete [] pairlist;
} }
} }
@ -527,44 +521,36 @@ void colvar::selfcoordnum::calc_gradients()
} }
void colvar::selfcoordnum::apply_force(colvarvalue const &force)
{
if (!group1->noforce) {
group1->apply_colvar_force(force.real_value);
}
}
colvar::groupcoordnum::groupcoordnum()
simple_scalar_dist_functions(selfcoordnum)
// groupcoordnum member functions
colvar::groupcoordnum::groupcoordnum(std::string const &conf)
: distance(conf), b_anisotropic(false)
{ {
set_function_type("groupCoord"); set_function_type("groupCoord");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
r0 = proxy->angstrom_to_internal(4.0);
r0_vec = cvm::rvector(proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0));
}
int colvar::groupcoordnum::init(std::string const &conf)
{
int error_code = distance::init(conf);
// group1 and group2 are already initialized by distance() // group1 and group2 are already initialized by distance()
if (group1->b_dummy || group2->b_dummy) { if (group1->b_dummy || group2->b_dummy) {
cvm::error("Error: neither group can be a dummy atom\n"); return cvm::error("Error: neither group can be a dummy atom\n", COLVARS_INPUT_ERROR);
return;
} }
bool const b_scale = get_keyval(conf, "cutoff", r0, bool const b_scale = get_keyval(conf, "cutoff", r0, r0);
cvm::real(proxy->angstrom_to_internal(4.0)));
if (get_keyval(conf, "cutoff3", r0_vec,
cvm::rvector(4.0, 4.0, 4.0), parse_silent)) {
if (get_keyval(conf, "cutoff3", r0_vec, r0_vec)) {
if (b_scale) { if (b_scale) {
cvm::error("Error: cannot specify \"scale\" and " error_code |=
"\"scale3\" at the same time.\n"); cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" at the same time.\n",
return; COLVARS_INPUT_ERROR);
} }
b_anisotropic = true; b_anisotropic = true;
// remove meaningless negative signs // remove meaningless negative signs
@ -573,23 +559,23 @@ colvar::groupcoordnum::groupcoordnum(std::string const &conf)
if (r0_vec.z < 0.0) r0_vec.z *= -1.0; if (r0_vec.z < 0.0) r0_vec.z *= -1.0;
} }
get_keyval(conf, "expNumer", en, 6); get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, 12); get_keyval(conf, "expDenom", ed, ed);
if ( (en%2) || (ed%2) ) { if ((en % 2) || (ed % 2)) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", error_code |= cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ((en <= 0) || (ed <= 0)) {
cvm::error("Error: negative exponent(s) provided.\n", error_code |= cvm::error("Error: negative exponent(s) provided.\n", COLVARS_INPUT_ERROR);
COLVARS_INPUT_ERROR);
} }
if (!is_enabled(f_cvc_pbc_minimum_image)) { if (!is_enabled(f_cvc_pbc_minimum_image)) {
cvm::log("Warning: only minimum-image distances are used by this variable.\n"); cvm::log("Warning: only minimum-image distances are used by this variable.\n");
} }
return error_code;
} }
@ -640,16 +626,3 @@ void colvar::groupcoordnum::calc_gradients()
group1->set_weighted_gradient(group1_com_atom.grad); group1->set_weighted_gradient(group1_com_atom.grad);
group2->set_weighted_gradient(group2_com_atom.grad); group2->set_weighted_gradient(group2_com_atom.grad);
} }
void colvar::groupcoordnum::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(groupcoordnum)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
#if (__cplusplus >= 201103L) // -*- c++ -*-
// This file is part of the Collective Variables module (Colvars). // This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at: // The original version of Colvars and its updates are located at:
@ -10,17 +10,29 @@
#include <numeric> #include <numeric>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstdlib>
#include <limits> #include <limits>
#include <fstream> #include <fstream>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(conf), atoms(nullptr), reference_frames(0) {
colvar::CartesianBasedPath::CartesianBasedPath()
{
x.type(colvarvalue::type_scalar);
// Don't use implicit gradient
enable(f_cvc_explicit_gradient);
}
int colvar::CartesianBasedPath::init(std::string const &conf)
{
int error_code = cvc::init(conf);
if (error_code != COLVARS_OK) return error_code;
// Parse selected atoms // Parse selected atoms
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
has_user_defined_fitting = false; has_user_defined_fitting = false;
@ -31,13 +43,12 @@ colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(con
// Lookup reference column of PDB // Lookup reference column of PDB
// Copied from the RMSD class // Copied from the RMSD class
std::string reference_column; std::string reference_column;
double reference_column_value; double reference_column_value = 0.0;
if (get_keyval(conf, "refPositionsCol", reference_column, std::string(""))) { if (get_keyval(conf, "refPositionsCol", reference_column, std::string(""))) {
bool found = get_keyval(conf, "refPositionsColValue", reference_column_value, 0.0); bool found = get_keyval(conf, "refPositionsColValue", reference_column_value, reference_column_value);
if (found && reference_column_value == 0.0) { if (found && reference_column_value == 0.0) {
cvm::error("Error: refPositionsColValue, " return cvm::error("Error: refPositionsColValue, if provided, must be non-zero.\n",
"if provided, must be non-zero.\n"); COLVARS_INPUT_ERROR);
return;
} }
} }
// Lookup all reference frames // Lookup all reference frames
@ -66,9 +77,6 @@ colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(con
tmp_atoms->ref_pos = reference_frames[i_frame]; tmp_atoms->ref_pos = reference_frames[i_frame];
tmp_atoms->center_ref_pos(); tmp_atoms->center_ref_pos();
tmp_atoms->enable(f_ag_fit_gradients); tmp_atoms->enable(f_ag_fit_gradients);
tmp_atoms->rot.request_group1_gradients(tmp_atoms->size());
tmp_atoms->rot.request_group2_gradients(tmp_atoms->size());
comp_atoms.push_back(tmp_atoms);
} else { } else {
// parse a group of atoms for fitting // parse a group of atoms for fitting
std::string fitting_group_name = std::string("fittingAtoms") + cvm::to_str(i_frame); std::string fitting_group_name = std::string("fittingAtoms") + cvm::to_str(i_frame);
@ -91,15 +99,13 @@ colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(con
tmp_atoms->enable(f_ag_fit_gradients); tmp_atoms->enable(f_ag_fit_gradients);
tmp_atoms->enable(f_ag_fitting_group); tmp_atoms->enable(f_ag_fitting_group);
tmp_atoms->fitting_group = tmp_fitting_atoms; tmp_atoms->fitting_group = tmp_fitting_atoms;
tmp_atoms->rot.request_group1_gradients(tmp_fitting_atoms->size());
tmp_atoms->rot.request_group2_gradients(tmp_fitting_atoms->size());
reference_fitting_frames.push_back(reference_fitting_position); reference_fitting_frames.push_back(reference_fitting_position);
comp_atoms.push_back(tmp_atoms);
} }
tmp_atoms->setup_rotation_derivative();
comp_atoms.push_back(tmp_atoms);
} }
x.type(colvarvalue::type_scalar);
// Don't use implicit gradient return error_code;
enable(f_cvc_explicit_gradient);
} }
colvar::CartesianBasedPath::~CartesianBasedPath() { colvar::CartesianBasedPath::~CartesianBasedPath() {
@ -125,8 +131,60 @@ void colvar::CartesianBasedPath::computeDistanceToReferenceFrames(std::vector<cv
} }
} }
colvar::gspath::gspath(std::string const &conf): CartesianBasedPath(conf) { // mainly used for determining the lambda value for arithmetic path
void colvar::CartesianBasedPath::computeDistanceBetweenReferenceFrames(std::vector<cvm::real>& result) {
for (size_t i_frame = 0; i_frame < reference_frames.size() - 1; ++i_frame) {
std::vector<cvm::atom_pos> this_frame_atom_pos(reference_frames[i_frame].size());
std::vector<cvm::atom_pos> next_frame_atom_pos(reference_frames[i_frame + 1].size());
cvm::real frame_rmsd = 0.0;
const size_t this_index = i_frame;
const size_t next_index = i_frame + 1;
// compute COM of two successive images, respectively
cvm::atom_pos reference_cog_this, reference_cog_next;
for (size_t i_atom = 0; i_atom < atoms->size(); ++i_atom) {
reference_cog_this += reference_frames[this_index][i_atom];
reference_cog_next += reference_frames[next_index][i_atom];
}
reference_cog_this /= reference_frames[this_index].size();
reference_cog_next /= reference_frames[next_index].size();
// move all atoms to COM
for (size_t i_atom = 0; i_atom < atoms->size(); ++i_atom) {
this_frame_atom_pos[i_atom] = reference_frames[this_index][i_atom] - reference_cog_this;
next_frame_atom_pos[i_atom] = reference_frames[next_index][i_atom] - reference_cog_next;
}
cvm::rotation rot_this_to_next;
// compute the optimal rotation
rot_this_to_next.calc_optimal_rotation(this_frame_atom_pos, next_frame_atom_pos);
// compute rmsd between reference frames
for (size_t i_atom = 0; i_atom < atoms->size(); ++i_atom) {
frame_rmsd += (rot_this_to_next.q.rotate(this_frame_atom_pos[i_atom]) - next_frame_atom_pos[i_atom]).norm2();
}
frame_rmsd /= cvm::real(atoms->size());
frame_rmsd = cvm::sqrt(frame_rmsd);
result[i_frame] = frame_rmsd;
}
}
void colvar::CartesianBasedPath::apply_force(colvarvalue const &force)
{
cvm::error("Error: using apply_force() in a component of type CartesianBasedPath, which is abstract.\n",
COLVARS_BUG_ERROR);
}
colvar::gspath::gspath()
{
set_function_type("gspath"); set_function_type("gspath");
}
int colvar::gspath::init(std::string const &conf)
{
int error_code = CartesianBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true);
if (use_second_closest_frame == true) { if (use_second_closest_frame == true) {
cvm::log(std::string("Geometric path s(σ) will use the second closest frame to compute s_(m-1)\n")); cvm::log(std::string("Geometric path s(σ) will use the second closest frame to compute s_(m-1)\n"));
@ -140,12 +198,14 @@ colvar::gspath::gspath(std::string const &conf): CartesianBasedPath(conf) {
cvm::log(std::string("Geometric path s(σ) will use the neighbouring frame to compute s_(m+1)\n")); cvm::log(std::string("Geometric path s(σ) will use the neighbouring frame to compute s_(m+1)\n"));
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspath requires at least 2 frames.\n"); return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) +
return; " reference frames, but gspath requires at least 2 frames.\n",
COLVARS_INPUT_ERROR);
} }
GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::S>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame); GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::S>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame);
cvm::log(std::string("Geometric pathCV(s) is initialized.\n")); cvm::log(std::string("Geometric pathCV(s) is initialized.\n"));
cvm::log(std::string("Geometric pathCV(s) loaded ") + cvm::to_str(reference_frames.size()) + std::string(" frames.\n")); cvm::log(std::string("Geometric pathCV(s) loaded ") + cvm::to_str(reference_frames.size()) + std::string(" frames.\n"));
return error_code;
} }
void colvar::gspath::updateDistanceToReferenceFrames() { void colvar::gspath::updateDistanceToReferenceFrames() {
@ -192,8 +252,9 @@ void colvar::gspath::prepareVectors() {
} else { } else {
rot_v3.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_2); rot_v3.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_2);
} }
const auto rot_mat_v3 = rot_v3.matrix();
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
v3[i_atom] = rot_v3.q.rotate(tmp_reference_frame_1[i_atom]) - tmp_reference_frame_2[i_atom]; v3[i_atom] = rot_mat_v3 * tmp_reference_frame_1[i_atom] - tmp_reference_frame_2[i_atom];
} }
} else { } else {
cvm::atom_pos reference_cog_1, reference_cog_3; cvm::atom_pos reference_cog_1, reference_cog_3;
@ -227,9 +288,10 @@ void colvar::gspath::prepareVectors() {
} else { } else {
rot_v3.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_3); rot_v3.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_3);
} }
const auto rot_mat_v3 = rot_v3.matrix();
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
// v3 = s_(m+1) - s_m // v3 = s_(m+1) - s_m
v3[i_atom] = tmp_reference_frame_3[i_atom] - rot_v3.q.rotate(tmp_reference_frame_1[i_atom]); v3[i_atom] = tmp_reference_frame_3[i_atom] - rot_mat_v3 * tmp_reference_frame_1[i_atom];
} }
} }
} }
@ -267,8 +329,17 @@ void colvar::gspath::apply_force(colvarvalue const &force) {
(*(comp_atoms[min_frame_index_2])).apply_colvar_force(F); (*(comp_atoms[min_frame_index_2])).apply_colvar_force(F);
} }
colvar::gzpath::gzpath(std::string const &conf): CartesianBasedPath(conf) {
colvar::gzpath::gzpath()
{
set_function_type("gzpath"); set_function_type("gzpath");
}
int colvar::gzpath::init(std::string const &conf)
{
int error_code = CartesianBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true);
if (use_second_closest_frame == true) { if (use_second_closest_frame == true) {
cvm::log(std::string("Geometric path z(σ) will use the second closest frame to compute s_(m-1)\n")); cvm::log(std::string("Geometric path z(σ) will use the second closest frame to compute s_(m-1)\n"));
@ -287,13 +358,15 @@ colvar::gzpath::gzpath(std::string const &conf): CartesianBasedPath(conf) {
cvm::log(std::string("Geometric path z(σ) will use the square of distance from current frame to path compute z\n")); cvm::log(std::string("Geometric path z(σ) will use the square of distance from current frame to path compute z\n"));
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpath requires at least 2 frames.\n"); return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) +
return; " reference frames, but gzpath requires at least 2 frames.\n",
COLVARS_INPUT_ERROR);
} }
GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::Z>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square); GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::Z>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square);
// Logging // Logging
cvm::log(std::string("Geometric pathCV(z) is initialized.\n")); cvm::log(std::string("Geometric pathCV(z) is initialized.\n"));
cvm::log(std::string("Geometric pathCV(z) loaded ") + cvm::to_str(reference_frames.size()) + std::string(" frames.\n")); cvm::log(std::string("Geometric pathCV(z) loaded ") + cvm::to_str(reference_frames.size()) + std::string(" frames.\n"));
return error_code;
} }
void colvar::gzpath::updateDistanceToReferenceFrames() { void colvar::gzpath::updateDistanceToReferenceFrames() {
@ -335,12 +408,13 @@ void colvar::gzpath::prepareVectors() {
} else { } else {
rot_v4.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_2); rot_v4.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_2);
} }
const auto rot_mat_v4 = rot_v4.matrix();
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
v1[i_atom] = reference_frames[min_frame_index_1][i_atom] - (*(comp_atoms[min_frame_index_1]))[i_atom].pos; v1[i_atom] = reference_frames[min_frame_index_1][i_atom] - (*(comp_atoms[min_frame_index_1]))[i_atom].pos;
v2[i_atom] = (*(comp_atoms[min_frame_index_2]))[i_atom].pos - reference_frames[min_frame_index_2][i_atom]; v2[i_atom] = (*(comp_atoms[min_frame_index_2]))[i_atom].pos - reference_frames[min_frame_index_2][i_atom];
// v4 only computes in gzpath // v4 only computes in gzpath
// v4 = s_m - s_(m-1) // v4 = s_m - s_(m-1)
v4[i_atom] = rot_v4.q.rotate(tmp_reference_frame_1[i_atom]) - tmp_reference_frame_2[i_atom]; v4[i_atom] = rot_mat_v4 * tmp_reference_frame_1[i_atom] - tmp_reference_frame_2[i_atom];
} }
if (min_frame_index_3 < 0 || min_frame_index_3 > M) { if (min_frame_index_3 < 0 || min_frame_index_3 > M) {
v3 = v4; v3 = v4;
@ -368,9 +442,10 @@ void colvar::gzpath::prepareVectors() {
} else { } else {
rot_v3.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_3); rot_v3.calc_optimal_rotation(tmp_reference_frame_1, tmp_reference_frame_3);
} }
const auto rot_mat_v3 = rot_v3.matrix();
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
// v3 = s_(m+1) - s_m // v3 = s_(m+1) - s_m
v3[i_atom] = tmp_reference_frame_3[i_atom] - rot_v3.q.rotate(tmp_reference_frame_1[i_atom]); v3[i_atom] = tmp_reference_frame_3[i_atom] - rot_mat_v3 * tmp_reference_frame_1[i_atom];
} }
} }
} }
@ -399,14 +474,26 @@ void colvar::gzpath::apply_force(colvarvalue const &force) {
} }
colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) { colvar::CVBasedPath::CVBasedPath()
{
set_function_type("gspathCV");
x.type(colvarvalue::type_scalar);
}
int colvar::CVBasedPath::init(std::string const &conf)
{
int error_code = cvc::init(conf);
if (error_code != COLVARS_OK) return error_code;
// Lookup all available sub-cvcs // Lookup all available sub-cvcs
for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) { for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) {
if (key_lookup(conf, it_cv_map->first.c_str())) { if (key_lookup(conf, it_cv_map->first.c_str())) {
std::vector<std::string> sub_cvc_confs; std::vector<std::string> sub_cvc_confs;
get_key_string_multi_value(conf, it_cv_map->first.c_str(), sub_cvc_confs); get_key_string_multi_value(conf, it_cv_map->first.c_str(), sub_cvc_confs);
for (auto it_sub_cvc_conf = sub_cvc_confs.begin(); it_sub_cvc_conf != sub_cvc_confs.end(); ++it_sub_cvc_conf) { for (auto it_sub_cvc_conf = sub_cvc_confs.begin(); it_sub_cvc_conf != sub_cvc_confs.end(); ++it_sub_cvc_conf) {
cv.push_back((it_cv_map->second)(*(it_sub_cvc_conf))); cv.push_back((it_cv_map->second)());
cv.back()->init(*(it_sub_cvc_conf));
} }
} }
} }
@ -429,7 +516,7 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
cvm::log(std::string("Reading path file: ") + path_filename + std::string("\n")); cvm::log(std::string("Reading path file: ") + path_filename + std::string("\n"));
auto &ifs_path = cvm::main()->proxy->input_stream(path_filename); auto &ifs_path = cvm::main()->proxy->input_stream(path_filename);
if (!ifs_path) { if (!ifs_path) {
return; return COLVARS_INPUT_ERROR;
} }
std::string line; std::string line;
const std::string token(" "); const std::string token(" ");
@ -450,8 +537,8 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
cvm::log(cvm::to_str(tmp_cv[i_cv][i - start_index])); cvm::log(cvm::to_str(tmp_cv[i_cv][i - start_index]));
} }
} else { } else {
cvm::error("Error: incorrect format of path file.\n"); error_code = cvm::error("Error: incorrect format of path file.\n", COLVARS_INPUT_ERROR);
return; return error_code;
} }
} }
if (!fields.empty()) { if (!fields.empty()) {
@ -461,15 +548,18 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
} }
cvm::main()->proxy->close_input_stream(path_filename); cvm::main()->proxy->close_input_stream(path_filename);
if (total_reference_frames <= 1) { if (total_reference_frames <= 1) {
cvm::error("Error: there is only 1 or 0 reference frame, which doesn't constitute a path.\n"); error_code = cvm::error(
return; "Error: there is only 1 or 0 reference frame, which doesn't constitute a path.\n",
COLVARS_INPUT_ERROR);
return error_code;
} }
if (cv.size() == 0) { if (cv.size() == 0) {
cvm::error("Error: the CV " + name + error_code =
" expects one or more nesting components.\n"); cvm::error("Error: the CV " + name + " expects one or more nesting components.\n",
return; COLVARS_INPUT_ERROR);
return error_code;
} }
x.type(colvarvalue::type_scalar);
use_explicit_gradients = true; use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) { if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
@ -479,6 +569,8 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
if (!use_explicit_gradients) { if (!use_explicit_gradients) {
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
} }
return error_code;
} }
void colvar::CVBasedPath::computeDistanceToReferenceFrames(std::vector<cvm::real>& result) { void colvar::CVBasedPath::computeDistanceToReferenceFrames(std::vector<cvm::real>& result) {
@ -548,8 +640,47 @@ colvar::CVBasedPath::~CVBasedPath() {
atom_groups.clear(); atom_groups.clear();
} }
colvar::gspathCV::gspathCV(std::string const &conf): CVBasedPath(conf) {
void colvar::CVBasedPath::apply_force(colvarvalue const &force)
{
cvm::error("Error: using apply_force() in a component of type CVBasedPath, which is abstract.\n",
COLVARS_BUG_ERROR);
}
cvm::real colvar::CVBasedPath::dist2(colvarvalue const &x1, colvarvalue const &x2) const
{
return x1.dist2(x2);
}
colvarvalue colvar::CVBasedPath::dist2_lgrad(colvarvalue const &x1, colvarvalue const &x2) const
{
return x1.dist2_grad(x2);
}
colvarvalue colvar::CVBasedPath::dist2_rgrad(colvarvalue const &x1, colvarvalue const &x2) const
{
return x2.dist2_grad(x1);
}
void colvar::CVBasedPath::wrap(colvarvalue & /* x_unwrapped */) const {}
colvar::gspathCV::gspathCV()
{
set_function_type("gspathCV"); set_function_type("gspathCV");
x.type(colvarvalue::type_scalar);
}
int colvar::gspathCV::init(std::string const &conf)
{
int error_code = CVBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
// Initialize variables for future calculation // Initialize variables for future calculation
get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true);
@ -565,11 +696,10 @@ colvar::gspathCV::gspathCV(std::string const &conf): CVBasedPath(conf) {
cvm::log(std::string("Geometric path s(σ) will use the neighbouring frame to compute s_(m+1)\n")); cvm::log(std::string("Geometric path s(σ) will use the neighbouring frame to compute s_(m+1)\n"));
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspathCV requires at least 2 frames.\n"); return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspathCV requires at least 2 frames.\n", COLVARS_INPUT_ERROR);
return;
} }
GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::S>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame); GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::S>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame);
x.type(colvarvalue::type_scalar); return error_code;
} }
colvar::gspathCV::~gspathCV() {} colvar::gspathCV::~gspathCV() {}
@ -671,8 +801,16 @@ void colvar::gspathCV::apply_force(colvarvalue const &force) {
} }
} }
colvar::gzpathCV::gzpathCV(std::string const &conf): CVBasedPath(conf) { colvar::gzpathCV::gzpathCV()
{
set_function_type("gzpathCV"); set_function_type("gzpathCV");
}
int colvar::gzpathCV::init(std::string const &conf) {
int error_code = CVBasedPath::init(conf);
if (error_code != COLVARS_OK) return error_code;
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
// Initialize variables for future calculation // Initialize variables for future calculation
M = cvm::real(total_reference_frames - 1); M = cvm::real(total_reference_frames - 1);
@ -695,11 +833,13 @@ colvar::gzpathCV::gzpathCV(std::string const &conf): CVBasedPath(conf) {
cvm::log(std::string("Geometric path z(σ) will use the square of distance from current frame to path compute z\n")); cvm::log(std::string("Geometric path z(σ) will use the square of distance from current frame to path compute z\n"));
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpathCV requires at least 2 frames.\n"); return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) +
return; " reference frames, but gzpathCV requires at least 2 frames.\n",
COLVARS_INPUT_ERROR);
} }
GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::Z>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square); GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::Z>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square);
x.type(colvarvalue::type_scalar);
return error_code;
} }
colvar::gzpathCV::~gzpathCV() { colvar::gzpathCV::~gzpathCV() {
@ -794,5 +934,3 @@ void colvar::gzpathCV::apply_force(colvarvalue const &force) {
} }
} }
} }
#endif

View File

@ -1,16 +1,31 @@
#if (__cplusplus >= 201103L) // -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
#include "colvar_neuralnetworkcompute.h" #include "colvar_neuralnetworkcompute.h"
using namespace neuralnetworkCV; using namespace neuralnetworkCV;
colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination(conf) {
colvar::neuralNetwork::neuralNetwork()
{
set_function_type("neuralNetwork"); set_function_type("neuralNetwork");
}
int colvar::neuralNetwork::init(std::string const &conf)
{
int error_code = linearCombination::init(conf);
if (error_code != COLVARS_OK) return error_code;
// the output of neural network consists of multiple values // the output of neural network consists of multiple values
// read "output_component" key to determine it // read "output_component" key to determine it
get_keyval(conf, "output_component", m_output_index); get_keyval(conf, "output_component", m_output_index);
@ -59,8 +74,8 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
std::string function_name; std::string function_name;
get_keyval(conf, lookup_key.c_str(), function_name, std::string("")); get_keyval(conf, lookup_key.c_str(), function_name, std::string(""));
if (activation_function_map.find(function_name) == activation_function_map.end()) { if (activation_function_map.find(function_name) == activation_function_map.end()) {
cvm::error("Unknown activation function name: \"" + function_name + "\".\n"); return cvm::error("Unknown activation function name: \"" + function_name + "\".\n",
return; COLVARS_INPUT_ERROR);
} }
activation_functions.push_back(std::make_pair(false, function_name)); activation_functions.push_back(std::make_pair(false, function_name));
cvm::log(std::string{"The activation function for layer["} + cvm::to_str(num_activation_functions + 1) + std::string{"] is "} + function_name + '\n'); cvm::log(std::string{"The activation function for layer["} + cvm::to_str(num_activation_functions + 1) + std::string{"] is "} + function_name + '\n');
@ -79,11 +94,13 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
} }
// expect the three numbers are equal // expect the three numbers are equal
if ((num_layers_weight != num_layers_bias) || (num_layers_bias != num_activation_functions)) { if ((num_layers_weight != num_layers_bias) || (num_layers_bias != num_activation_functions)) {
cvm::error("Error: the numbers of weights, biases and activation functions do not match.\n"); return cvm::error(
return; "Error: the numbers of weights, biases and activation functions do not match.\n",
COLVARS_INPUT_ERROR);
} }
// nn = std::make_unique<neuralnetworkCV::neuralNetworkCompute>(); // nn = std::make_unique<neuralnetworkCV::neuralNetworkCompute>();
// std::make_unique is only available in C++14 // std::make_unique is only available in C++14
if (nn) nn.reset();
nn = std::unique_ptr<neuralnetworkCV::neuralNetworkCompute>(new neuralnetworkCV::neuralNetworkCompute()); nn = std::unique_ptr<neuralnetworkCV::neuralNetworkCompute>(new neuralnetworkCV::neuralNetworkCompute());
for (size_t i_layer = 0; i_layer < num_layers_weight; ++i_layer) { for (size_t i_layer = 0; i_layer < num_layers_weight; ++i_layer) {
denseLayer d; denseLayer d;
@ -93,8 +110,9 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
try { try {
d = denseLayer(weight_files[i_layer], bias_files[i_layer], activation_functions[i_layer].second); d = denseLayer(weight_files[i_layer], bias_files[i_layer], activation_functions[i_layer].second);
} catch (std::exception &ex) { } catch (std::exception &ex) {
cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR); return cvm::error("Error on initializing layer " + cvm::to_str(i_layer) +
return; " (" + ex.what() + ")\n",
COLVARS_INPUT_ERROR);
} }
} else { } else {
#endif #endif
@ -104,8 +122,9 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
try { try {
d = denseLayer(weight_files[i_layer], bias_files[i_layer], f, df); d = denseLayer(weight_files[i_layer], bias_files[i_layer], f, df);
} catch (std::exception &ex) { } catch (std::exception &ex) {
cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR); return cvm::error("Error on initializing layer " + cvm::to_str(i_layer) +
return; " (" + ex.what() + ")\n",
COLVARS_INPUT_ERROR);
} }
#ifdef LEPTON #ifdef LEPTON
} }
@ -123,11 +142,11 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
} }
} }
} else { } else {
cvm::error("Error: error on adding a new dense layer.\n"); return cvm::error("Error: error on adding a new dense layer.\n", COLVARS_INPUT_ERROR);
return;
} }
} }
nn->input().resize(cv.size()); nn->input().resize(cv.size());
return error_code;
} }
colvar::neuralNetwork::~neuralNetwork() { colvar::neuralNetwork::~neuralNetwork() {
@ -185,4 +204,24 @@ void colvar::neuralNetwork::apply_force(colvarvalue const &force) {
} }
} }
#endif
cvm::real colvar::neuralNetwork::dist2(colvarvalue const &x1, colvarvalue const &x2) const
{
return x1.dist2(x2);
}
colvarvalue colvar::neuralNetwork::dist2_lgrad(colvarvalue const &x1, colvarvalue const &x2) const
{
return x1.dist2_grad(x2);
}
colvarvalue colvar::neuralNetwork::dist2_rgrad(colvarvalue const &x1, colvarvalue const &x2) const
{
return x2.dist2_grad(x1);
}
void colvar::neuralNetwork::wrap(colvarvalue & /* x_unwrapped */) const {}

View File

@ -11,19 +11,23 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::alpha_angles::alpha_angles(std::string const &conf) colvar::alpha_angles::alpha_angles()
: cvc(conf)
{ {
set_function_type("alpha"); set_function_type("alpha");
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
r0 = proxy->angstrom_to_internal(3.3);
}
int colvar::alpha_angles::init(std::string const &conf)
{
int error_code = cvc::init(conf);
std::string segment_id; std::string segment_id;
get_keyval(conf, "psfSegID", segment_id, std::string("MAIN")); get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
@ -44,29 +48,29 @@ colvar::alpha_angles::alpha_angles(std::string const &conf)
} }
} }
} else { } else {
cvm::error("Error: no residues defined in \"residueRange\".\n"); error_code |=
return; cvm::error("Error: no residues defined in \"residueRange\".\n", COLVARS_INPUT_ERROR);
} }
} }
if (residues.size() < 5) { if (residues.size() < 5) {
cvm::error("Error: not enough residues defined in \"residueRange\".\n"); error_code |= cvm::error("Error: not enough residues defined in \"residueRange\".\n",
return; COLVARS_INPUT_ERROR);
} }
std::string const &sid = segment_id; std::string const &sid = segment_id;
std::vector<int> const &r = residues; std::vector<int> const &r = residues;
get_keyval(conf, "hBondCoeff", hb_coeff, 0.5); get_keyval(conf, "hBondCoeff", hb_coeff, hb_coeff);
if ( (hb_coeff < 0.0) || (hb_coeff > 1.0) ) { if ((hb_coeff < 0.0) || (hb_coeff > 1.0)) {
cvm::error("Error: hBondCoeff must be defined between 0 and 1.\n"); error_code |=
return; cvm::error("Error: hBondCoeff must be defined between 0 and 1.\n", COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "angleRef", theta_ref, 88.0); get_keyval(conf, "angleRef", theta_ref, theta_ref);
get_keyval(conf, "angleTol", theta_tol, 15.0); get_keyval(conf, "angleTol", theta_tol, theta_tol);
if (hb_coeff < 1.0) { if (hb_coeff < 1.0) {
@ -84,11 +88,9 @@ colvar::alpha_angles::alpha_angles(std::string const &conf)
} }
{ {
cvm::real r0; get_keyval(conf, "hBondCutoff", r0, r0);
size_t en, ed; get_keyval(conf, "hBondExpNumer", en, en);
get_keyval(conf, "hBondCutoff", r0, proxy->angstrom_to_internal(3.3)); get_keyval(conf, "hBondExpDenom", ed, ed);
get_keyval(conf, "hBondExpNumer", en, 6);
get_keyval(conf, "hBondExpDenom", ed, 8);
if (hb_coeff > 0.0) { if (hb_coeff > 0.0) {
@ -103,15 +105,8 @@ colvar::alpha_angles::alpha_angles(std::string const &conf)
cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n"); cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n");
} }
} }
}
return error_code;
colvar::alpha_angles::alpha_angles()
: cvc()
{
set_function_type("alphaAngles");
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
} }
@ -273,24 +268,27 @@ void colvar::alpha_angles::apply_force(colvarvalue const &force)
} }
simple_scalar_dist_functions(alpha_angles)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// dihedral principal component // dihedral principal component
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
colvar::dihedPC::dihedPC(std::string const &conf) colvar::dihedPC::dihedPC()
: cvc(conf)
{ {
if (cvm::debug())
cvm::log("Initializing dihedral PC object.\n");
set_function_type("dihedPC"); set_function_type("dihedPC");
// Supported through references to atom groups of children cvcs // Supported through references to atom groups of children cvcs
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
}
int colvar::dihedPC::init(std::string const &conf)
{
int error_code = cvc::init(conf);
if (cvm::debug())
cvm::log("Initializing dihedral PC object.\n");
std::string segment_id; std::string segment_id;
get_keyval(conf, "psfSegID", segment_id, std::string("MAIN")); get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
@ -311,14 +309,14 @@ colvar::dihedPC::dihedPC(std::string const &conf)
} }
} }
} else { } else {
cvm::error("Error: no residues defined in \"residueRange\".\n"); error_code |=
return; cvm::error("Error: no residues defined in \"residueRange\".\n", COLVARS_INPUT_ERROR);
} }
} }
if (residues.size() < 2) { if (residues.size() < 2) {
cvm::error("Error: dihedralPC requires at least two residues.\n"); error_code |=
return; cvm::error("Error: dihedralPC requires at least two residues.\n", COLVARS_INPUT_ERROR);
} }
std::string const &sid = segment_id; std::string const &sid = segment_id;
@ -329,15 +327,15 @@ colvar::dihedPC::dihedPC(std::string const &conf)
if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) { if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) {
get_keyval(conf, "vectorNumber", vecNumber, 0); get_keyval(conf, "vectorNumber", vecNumber, 0);
if (vecNumber < 1) { if (vecNumber < 1) {
cvm::error("A positive value of vectorNumber is required."); error_code |=
return; cvm::error("A positive value of vectorNumber is required.", COLVARS_INPUT_ERROR);
} }
std::istream &vecFile = std::istream &vecFile =
cvm::main()->proxy->input_stream(vecFileName, cvm::main()->proxy->input_stream(vecFileName,
"dihedral PCA vector file"); "dihedral PCA vector file");
if (!vecFile) { if (!vecFile) {
return; return COLVARS_INPUT_ERROR;
} }
// TODO: adapt to different formats by setting this flag // TODO: adapt to different formats by setting this flag
@ -383,11 +381,10 @@ colvar::dihedPC::dihedPC(std::string const &conf)
} }
if ( coeffs.size() != 4 * (residues.size() - 1)) { if ( coeffs.size() != 4 * (residues.size() - 1)) {
cvm::error("Error: wrong number of coefficients: " + error_code |= cvm::error("Error: wrong number of coefficients: " + cvm::to_str(coeffs.size()) +
cvm::to_str(coeffs.size()) + ". Expected " + ". Expected " + cvm::to_str(4 * (residues.size() - 1)) +
cvm::to_str(4 * (residues.size() - 1)) + " (4 coeffs per residue, minus one residue).\n",
" (4 coeffs per residue, minus one residue).\n"); COLVARS_INPUT_ERROR);
return;
} }
for (size_t i = 0; i < residues.size()-1; i++) { for (size_t i = 0; i < residues.size()-1; i++) {
@ -413,16 +410,8 @@ colvar::dihedPC::dihedPC(std::string const &conf)
if (cvm::debug()) if (cvm::debug())
cvm::log("Done initializing dihedPC object.\n"); cvm::log("Done initializing dihedPC object.\n");
}
return error_code;
colvar::dihedPC::dihedPC()
: cvc()
{
set_function_type("dihedPC");
// Supported through references to atom groups of children cvcs
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
} }
@ -491,6 +480,3 @@ void colvar::dihedPC::apply_force(colvarvalue const &force)
coeffs[2*i+1] * dsindt) * force); coeffs[2*i+1] * dsindt) * force);
} }
} }
simple_scalar_dist_functions(dihedPC)

View File

@ -9,27 +9,39 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
#include "colvar_rotation_derivative.h"
struct colvar::orientation::rotation_derivative_impl_: public rotation_derivative<cvm::atom_pos, cvm::atom_pos> {
public:
rotation_derivative_impl_(colvar::orientation* orientation_cvc):
rotation_derivative<cvm::atom_pos, cvm::atom_pos>(
orientation_cvc->rot, orientation_cvc->ref_pos, orientation_cvc->shifted_pos) {}
};
colvar::orientation::orientation(std::string const &conf)
: cvc() colvar::orientation::orientation()
{ {
set_function_type("orientation"); set_function_type("orientation");
rot_deriv_impl = std::unique_ptr<rotation_derivative_impl_>(new rotation_derivative_impl_(this));
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_quaternion); x.type(colvarvalue::type_quaternion);
colvar::orientation::init(conf);
} }
colvar::orientation::~orientation() {}
int colvar::orientation::init(std::string const &conf) int colvar::orientation::init(std::string const &conf)
{ {
int error_code = cvc::init(conf); int error_code = cvc::init(conf);
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
if (!atoms || atoms->size() == 0) {
return error_code | COLVARS_INPUT_ERROR;
}
ref_pos.reserve(atoms->size()); ref_pos.reserve(atoms->size());
if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) { if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) {
@ -56,17 +68,18 @@ int colvar::orientation::init(std::string const &conf)
} }
ref_pos.resize(atoms->size()); ref_pos.resize(atoms->size());
cvm::load_coords(file_name.c_str(), &ref_pos, atoms, error_code |= cvm::load_coords(file_name.c_str(), &ref_pos, atoms,
file_col, file_col_value); file_col, file_col_value);
} }
} }
if (error_code != COLVARS_OK) return error_code;
if (!ref_pos.size()) { if (!ref_pos.size()) {
return cvm::error("Error: must define a set of " return cvm::error("Error: must define a set of "
"reference coordinates.\n", COLVARS_INPUT_ERROR); "reference coordinates.\n", COLVARS_INPUT_ERROR);
} }
cvm::rvector ref_cog(0.0, 0.0, 0.0); cvm::rvector ref_cog(0.0, 0.0, 0.0);
size_t i; size_t i;
for (i = 0; i < ref_pos.size(); i++) { for (i = 0; i < ref_pos.size(); i++) {
@ -84,30 +97,21 @@ int colvar::orientation::init(std::string const &conf)
get_keyval(conf, "closestToQuaternion", ref_quat, cvm::quaternion(1.0, 0.0, 0.0, 0.0)); get_keyval(conf, "closestToQuaternion", ref_quat, cvm::quaternion(1.0, 0.0, 0.0, 0.0));
// initialize rot member data // If the debug gradients feature is active, debug the rotation gradients
if (!atoms->noforce) { // (note that this won't be active for the orientation CVC itself, because
rot.request_group2_gradients(atoms->size()); // colvardeps prevents the flag's activation)
} rot.b_debug_gradients = is_enabled(f_cvc_debug_gradient);
return error_code; return error_code;
} }
colvar::orientation::orientation()
: cvc()
{
set_function_type("orientation");
disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_quaternion);
}
void colvar::orientation::calc_value() void colvar::orientation::calc_value()
{ {
rot.b_debug_gradients = is_enabled(f_cvc_debug_gradient);
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
if ((rot.q).inner(ref_quat) >= 0.0) { if ((rot.q).inner(ref_quat) >= 0.0) {
x.quaternion_value = rot.q; x.quaternion_value = rot.q;
@ -131,9 +135,12 @@ void colvar::orientation::apply_force(colvarvalue const &force)
cvm::quaternion const &FQ = force.quaternion_value; cvm::quaternion const &FQ = force.quaternion_value;
if (!atoms->noforce) { if (!atoms->noforce) {
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < 4; i++) {
(*atoms)[ia].apply_force(FQ[i] * rot.dQ0_2[ia][i]); (*atoms)[ia].apply_force(FQ[i] * dq0_2[i]);
} }
} }
} }
@ -161,20 +168,15 @@ colvarvalue colvar::orientation::dist2_rgrad(colvarvalue const &x1,
} }
void colvar::orientation::wrap(colvarvalue & /* x_unwrapped */) const {}
colvar::orientation_angle::orientation_angle(std::string const &conf)
: orientation()
colvar::orientation_angle::orientation_angle()
{ {
set_function_type("orientationAngle"); set_function_type("orientationAngle");
init_as_angle(); init_as_angle();
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
orientation_angle::init(conf);
}
int colvar::orientation_angle::init(std::string const &conf)
{
return orientation::init(conf);
} }
@ -182,7 +184,8 @@ void colvar::orientation_angle::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
if ((rot.q).q0 >= 0.0) { if ((rot.q).q0 >= 0.0) {
x.real_value = (180.0/PI) * 2.0 * cvm::acos((rot.q).q0); x.real_value = (180.0/PI) * 2.0 * cvm::acos((rot.q).q0);
@ -199,46 +202,59 @@ void colvar::orientation_angle::calc_gradients()
((180.0 / PI) * (-2.0) / cvm::sqrt(1.0 - ((rot.q).q0 * (rot.q).q0))) : ((180.0 / PI) * (-2.0) / cvm::sqrt(1.0 - ((rot.q).q0 * (rot.q).q0))) :
0.0 ); 0.0 );
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]); rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(*atoms)[ia].grad = (dxdq0 * dq0_2[0]);
} }
} }
void colvar::orientation_angle::apply_force(colvarvalue const &force) void colvar::orientation_angle::apply_force(colvarvalue const &force)
{ {
cvm::real const &fw = force.real_value; cvc::apply_force(force);
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
} }
simple_scalar_dist_functions(orientation_angle) cvm::real colvar::orientation_angle::dist2(colvarvalue const &x1, colvarvalue const &x2) const
{
return cvc::dist2(x1, x2);
}
colvarvalue colvar::orientation_angle::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return cvc::dist2_lgrad(x1, x2);
}
colvarvalue colvar::orientation_angle::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return cvc::dist2_rgrad(x1, x2);
}
void colvar::orientation_angle::wrap(colvarvalue & /* x_unwrapped */) const {}
colvar::orientation_proj::orientation_proj(std::string const &conf) colvar::orientation_proj::orientation_proj()
: orientation()
{ {
set_function_type("orientationProj"); set_function_type("orientationProj");
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
orientation_proj::init(conf);
}
int colvar::orientation_proj::init(std::string const &conf)
{
return orientation::init(conf);
} }
void colvar::orientation_proj::calc_value() void colvar::orientation_proj::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
x.real_value = 2.0 * (rot.q).q0 * (rot.q).q0 - 1.0; x.real_value = 2.0 * (rot.q).q0 * (rot.q).q0 - 1.0;
} }
@ -246,42 +262,28 @@ void colvar::orientation_proj::calc_value()
void colvar::orientation_proj::calc_gradients() void colvar::orientation_proj::calc_gradients()
{ {
cvm::real const dxdq0 = 2.0 * 2.0 * (rot.q).q0; cvm::real const dxdq0 = 2.0 * 2.0 * (rot.q).q0;
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]); rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(*atoms)[ia].grad = (dxdq0 * dq0_2[0]);
} }
} }
void colvar::orientation_proj::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) { colvar::tilt::tilt()
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(orientation_proj)
colvar::tilt::tilt(std::string const &conf)
: orientation()
{ {
set_function_type("tilt"); set_function_type("tilt");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
init_scalar_boundaries(-1.0, 1.0); init_scalar_boundaries(-1.0, 1.0);
tilt::init(conf);
} }
int colvar::tilt::init(std::string const &conf) int colvar::tilt::init(std::string const &conf)
{ {
int error_code = COLVARS_OK; int error_code = orientation_proj::init(conf);
error_code |= orientation::init(conf);
get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0)); get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
if (axis.norm2() != 1.0) { if (axis.norm2() != 1.0) {
@ -297,7 +299,8 @@ void colvar::tilt::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
x.real_value = rot.cos_theta(axis); x.real_value = rot.cos_theta(axis);
} }
@ -307,64 +310,24 @@ void colvar::tilt::calc_gradients()
{ {
cvm::quaternion const dxdq = rot.dcos_theta_dq(axis); cvm::quaternion const dxdq = rot.dcos_theta_dq(axis);
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0); (*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0);
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
for (size_t iq = 0; iq < 4; iq++) { for (size_t iq = 0; iq < 4; iq++) {
(*atoms)[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]); (*atoms)[ia].grad += (dxdq[iq] * dq0_2[iq]);
} }
} }
} }
void colvar::tilt::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) { colvar::spin_angle::spin_angle()
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(tilt)
colvar::spin_angle::spin_angle(std::string const &conf)
: orientation()
{ {
set_function_type("spinAngle"); set_function_type("spinAngle");
init_as_periodic_angle(); init_as_periodic_angle();
enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
spin_angle::init(conf);
}
int colvar::spin_angle::init(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= orientation::init(conf);
get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
if (axis.norm2() != 1.0) {
axis /= axis.norm();
cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n");
}
return error_code;
}
colvar::spin_angle::spin_angle()
: orientation()
{
set_function_type("spinAngle");
period = 360.0;
enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
} }
@ -372,10 +335,11 @@ void colvar::spin_angle::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
x.real_value = rot.spin_angle(axis); x.real_value = rot.spin_angle(axis);
this->wrap(x); wrap(x);
} }
@ -383,80 +347,20 @@ void colvar::spin_angle::calc_gradients()
{ {
cvm::quaternion const dxdq = rot.dspin_angle_dq(axis); cvm::quaternion const dxdq = rot.dspin_angle_dq(axis);
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0); (*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0);
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
for (size_t iq = 0; iq < 4; iq++) { for (size_t iq = 0; iq < 4; iq++) {
(*atoms)[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]); (*atoms)[ia].grad += (dxdq[iq] * dq0_2[iq]);
} }
} }
} }
void colvar::spin_angle::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
cvm::real colvar::spin_angle::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::spin_angle::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::spin_angle::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::spin_angle::wrap(colvarvalue &x_unwrapped) const
{
if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
x_unwrapped.real_value -= 360.0;
return;
}
if ((x_unwrapped.real_value - wrap_center) < -180.0) {
x_unwrapped.real_value += 360.0;
return;
}
return;
}
colvar::euler_phi::euler_phi(std::string const &conf)
: orientation()
{
set_function_type("eulerPhi");
init_as_periodic_angle();
enable(f_cvc_explicit_gradient);
euler_phi::init(conf);
}
colvar::euler_phi::euler_phi() colvar::euler_phi::euler_phi()
: orientation()
{ {
set_function_type("eulerPhi"); set_function_type("eulerPhi");
init_as_periodic_angle(); init_as_periodic_angle();
@ -464,19 +368,12 @@ colvar::euler_phi::euler_phi()
} }
int colvar::euler_phi::init(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= orientation::init(conf);
return error_code;
}
void colvar::euler_phi::calc_value() void colvar::euler_phi::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
const cvm::real& q0 = rot.q.q0; const cvm::real& q0 = rot.q.q0;
const cvm::real& q1 = rot.q.q1; const cvm::real& q1 = rot.q.q1;
@ -499,79 +396,20 @@ void colvar::euler_phi::calc_gradients()
const cvm::real dxdq1 = (180.0/PI) * (2 * q0 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) - 4 * q1 * (-2 * q0 * q1 - 2 * q2 * q3)) / denominator; const cvm::real dxdq1 = (180.0/PI) * (2 * q0 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) - 4 * q1 * (-2 * q0 * q1 - 2 * q2 * q3)) / denominator;
const cvm::real dxdq2 = (180.0/PI) * (-4 * q2 * (-2 * q0 * q1 - 2 * q2 * q3) + 2 * q3 * (-2 * q1 * q1 - 2 * q2 * q2 + 1)) / denominator; const cvm::real dxdq2 = (180.0/PI) * (-4 * q2 * (-2 * q0 * q1 - 2 * q2 * q3) + 2 * q3 * (-2 * q1 * q1 - 2 * q2 * q2 + 1)) / denominator;
const cvm::real dxdq3 = (180.0/PI) * 2 * q2 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) / denominator; const cvm::real dxdq3 = (180.0/PI) * 2 * q2 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) / denominator;
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) + rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(dxdq1 * (rot.dQ0_2[ia])[1]) + (*atoms)[ia].grad = (dxdq0 * dq0_2[0]) +
(dxdq2 * (rot.dQ0_2[ia])[2]) + (dxdq1 * dq0_2[1]) +
(dxdq3 * (rot.dQ0_2[ia])[3]); (dxdq2 * dq0_2[2]) +
(dxdq3 * dq0_2[3]);
} }
} }
void colvar::euler_phi::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
cvm::real colvar::euler_phi::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::euler_phi::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::euler_phi::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::euler_phi::wrap(colvarvalue &x_unwrapped) const
{
if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
x_unwrapped.real_value -= 360.0;
return;
}
if ((x_unwrapped.real_value - wrap_center) < -180.0) {
x_unwrapped.real_value += 360.0;
return;
}
return;
}
colvar::euler_psi::euler_psi(std::string const &conf)
: orientation()
{
set_function_type("eulerPsi");
init_as_periodic_angle();
enable(f_cvc_explicit_gradient);
euler_psi::init(conf);
}
colvar::euler_psi::euler_psi() colvar::euler_psi::euler_psi()
: orientation()
{ {
set_function_type("eulerPsi"); set_function_type("eulerPsi");
init_as_periodic_angle(); init_as_periodic_angle();
@ -579,19 +417,12 @@ colvar::euler_psi::euler_psi()
} }
int colvar::euler_psi::init(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= orientation::init(conf);
return error_code;
}
void colvar::euler_psi::calc_value() void colvar::euler_psi::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
const cvm::real& q0 = rot.q.q0; const cvm::real& q0 = rot.q.q0;
const cvm::real& q1 = rot.q.q1; const cvm::real& q1 = rot.q.q1;
@ -614,79 +445,20 @@ void colvar::euler_psi::calc_gradients()
const cvm::real dxdq1 = (180.0/PI) * 2 * q2 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) / denominator; const cvm::real dxdq1 = (180.0/PI) * 2 * q2 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) / denominator;
const cvm::real dxdq2 = (180.0/PI) * (2 * q1 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) - 4 * q2 * (-2 * q0 * q3 - 2 * q1 * q2)) / denominator; const cvm::real dxdq2 = (180.0/PI) * (2 * q1 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) - 4 * q2 * (-2 * q0 * q3 - 2 * q1 * q2)) / denominator;
const cvm::real dxdq3 = (180.0/PI) * (2 * q0 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) - 4 * q3 * (-2 * q0 * q3 - 2 * q1 * q2)) / denominator; const cvm::real dxdq3 = (180.0/PI) * (2 * q0 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) - 4 * q3 * (-2 * q0 * q3 - 2 * q1 * q2)) / denominator;
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) + rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(dxdq1 * (rot.dQ0_2[ia])[1]) + (*atoms)[ia].grad = (dxdq0 * dq0_2[0]) +
(dxdq2 * (rot.dQ0_2[ia])[2]) + (dxdq1 * dq0_2[1]) +
(dxdq3 * (rot.dQ0_2[ia])[3]); (dxdq2 * dq0_2[2]) +
(dxdq3 * dq0_2[3]);
} }
} }
void colvar::euler_psi::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
cvm::real colvar::euler_psi::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::euler_psi::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::euler_psi::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::euler_psi::wrap(colvarvalue &x_unwrapped) const
{
if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
x_unwrapped.real_value -= 360.0;
return;
}
if ((x_unwrapped.real_value - wrap_center) < -180.0) {
x_unwrapped.real_value += 360.0;
return;
}
return;
}
colvar::euler_theta::euler_theta(std::string const &conf)
: orientation()
{
set_function_type("eulerTheta");
init_as_angle();
enable(f_cvc_explicit_gradient);
euler_theta::init(conf);
}
colvar::euler_theta::euler_theta() colvar::euler_theta::euler_theta()
: orientation()
{ {
set_function_type("eulerTheta"); set_function_type("eulerTheta");
init_as_angle(); init_as_angle();
@ -694,19 +466,12 @@ colvar::euler_theta::euler_theta()
} }
int colvar::euler_theta::init(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= orientation::init(conf);
return error_code;
}
void colvar::euler_theta::calc_value() void colvar::euler_theta::calc_value()
{ {
atoms_cog = atoms->center_of_geometry(); atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog)); shifted_pos = atoms->positions_shifted(-1.0 * atoms_cog);
rot.calc_optimal_rotation(ref_pos, shifted_pos);
const cvm::real& q0 = rot.q.q0; const cvm::real& q0 = rot.q.q0;
const cvm::real& q1 = rot.q.q1; const cvm::real& q1 = rot.q.q1;
@ -727,43 +492,13 @@ void colvar::euler_theta::calc_gradients()
const cvm::real dxdq1 = (180.0/PI) * -2 * q3 / denominator; const cvm::real dxdq1 = (180.0/PI) * -2 * q3 / denominator;
const cvm::real dxdq2 = (180.0/PI) * 2 * q0 / denominator; const cvm::real dxdq2 = (180.0/PI) * 2 * q0 / denominator;
const cvm::real dxdq3 = (180.0/PI) * -2 * q1 / denominator; const cvm::real dxdq3 = (180.0/PI) * -2 * q1 / denominator;
rot_deriv_impl->prepare_derivative(rotation_derivative_dldq::use_dq);
cvm::vector1d<cvm::rvector> dq0_2;
for (size_t ia = 0; ia < atoms->size(); ia++) { for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) + rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(dxdq1 * (rot.dQ0_2[ia])[1]) + (*atoms)[ia].grad = (dxdq0 * dq0_2[0]) +
(dxdq2 * (rot.dQ0_2[ia])[2]) + (dxdq1 * dq0_2[1]) +
(dxdq3 * (rot.dQ0_2[ia])[3]); (dxdq2 * dq0_2[2]) +
(dxdq3 * dq0_2[3]);
} }
} }
void colvar::euler_theta::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
cvm::real colvar::euler_theta::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
// theta angle is not periodic
return cvc::dist2(x1, x2);
}
colvarvalue colvar::euler_theta::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
// theta angle is not periodic
return cvc::dist2_lgrad(x1, x2);
}
colvarvalue colvar::euler_theta::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
// theta angle is not periodic
return cvc::dist2_rgrad(x1, x2);
}

View File

@ -9,35 +9,18 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::map_total::map_total() colvar::map_total::map_total()
: cvc()
{ {
set_function_type("mapTotal"); set_function_type("mapTotal");
volmap_id = -1;
volmap_index = -1;
atoms = NULL;
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
} }
colvar::map_total::map_total(std::string const &conf)
: cvc() // init() will take care of this
{
set_function_type("mapTotal");
volmap_id = -1;
volmap_index = -1;
atoms = NULL;
x.type(colvarvalue::type_scalar);
map_total::init(conf);
}
int colvar::map_total::init(std::string const &conf) int colvar::map_total::init(std::string const &conf)
{ {
int error_code = cvc::init(conf); int error_code = cvc::init(conf);
@ -50,12 +33,12 @@ int colvar::map_total::init(std::string const &conf)
if ((volmap_name.size() > 0) && (volmap_id >= 0)) { if ((volmap_name.size() > 0) && (volmap_id >= 0)) {
error_code |= error_code |=
cvm::error("Error: mapName and mapID are mutually exclusive.\n"); cvm::error("Error: mapName and mapID are mutually exclusive.\n", COLVARS_INPUT_ERROR);
} }
// Parse optional group // Parse optional group
atoms = parse_group(conf, "atoms", true); atoms = parse_group(conf, "atoms", true);
if (atoms != NULL) { if (atoms) {
// Using internal selection // Using internal selection
if (volmap_name.size()) { if (volmap_name.size()) {
@ -74,11 +57,11 @@ int colvar::map_total::init(std::string const &conf)
if (volmap_id >= 0) { if (volmap_id >= 0) {
volmap_index = proxy->init_volmap_by_id(volmap_id); volmap_index = proxy->init_volmap_by_id(volmap_id);
} }
error_code |= volmap_index > 0 ? COLVARS_OK : COLVARS_INPUT_ERROR; error_code |= (volmap_index >= 0) ? COLVARS_OK : COLVARS_INPUT_ERROR;
} }
if (get_keyval(conf, "atomWeights", atom_weights, atom_weights)) { if (get_keyval(conf, "atomWeights", atom_weights, atom_weights)) {
if (atoms == NULL) { if (!atoms) {
error_code |= cvm::error("Error: weights can only be assigned when atoms " error_code |= cvm::error("Error: weights can only be assigned when atoms "
"are selected explicitly in Colvars.\n", "are selected explicitly in Colvars.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
@ -133,11 +116,10 @@ void colvar::map_total::calc_gradients()
void colvar::map_total::apply_force(colvarvalue const &force) void colvar::map_total::apply_force(colvarvalue const &force)
{ {
colvarproxy *proxy = cvm::main()->proxy;
if (atoms) { if (atoms) {
if (!atoms->noforce) cvc::apply_force(force);
atoms->apply_colvar_force(force.real_value);
} else { } else {
colvarproxy *proxy = cvm::main()->proxy;
proxy->apply_volmap_force(volmap_index, force.real_value); proxy->apply_volmap_force(volmap_index, force.real_value);
} }
} }

View File

@ -129,6 +129,11 @@ int colvardeps::enable(int feature_id,
int res; int res;
size_t i, j; size_t i, j;
bool ok; bool ok;
if (feature_id < 0 || feature_id >= int(features().size())) {
cvm::error("Error: colvardeps::enable() called with invalid feature_id " + cvm::to_str(feature_id) + "\n");
return COLVARS_ERROR;
}
feature *f = features()[feature_id]; feature *f = features()[feature_id];
feature_state *fs = &feature_states[feature_id]; feature_state *fs = &feature_states[feature_id];

View File

@ -253,6 +253,8 @@ public:
f_cvb_write_ti_pmf, f_cvb_write_ti_pmf,
/// \brief whether this bias uses an external grid to scale the biasing forces /// \brief whether this bias uses an external grid to scale the biasing forces
f_cvb_scale_biasing_force, f_cvb_scale_biasing_force,
/// \brief whether this bias is applied to one or more ext-Lagrangian colvars
f_cvb_extended,
f_cvb_ntot f_cvb_ntot
}; };
@ -355,6 +357,8 @@ public:
f_cvc_lower_boundary, f_cvc_lower_boundary,
/// This CVC provides a default value for the colvar's upper boundary /// This CVC provides a default value for the colvar's upper boundary
f_cvc_upper_boundary, f_cvc_upper_boundary,
/// CVC accesses atom groups directly (as opposed to going throuh other objects)
f_cvc_explicit_atom_groups,
/// CVC calculates atom gradients /// CVC calculates atom gradients
f_cvc_gradient, f_cvc_gradient,
/// CVC calculates and stores explicit atom gradients on rank 0 /// CVC calculates and stores explicit atom gradients on rank 0

View File

@ -8,13 +8,11 @@
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <ctime> #include <ctime>
#include <fstream>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h" #include "colvarparse.h"
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h"
#include "colvargrid.h" #include "colvargrid.h"
#include "colvargrid_def.h" #include "colvargrid_def.h"
@ -37,6 +35,58 @@ colvar_grid_count::colvar_grid_count(std::vector<colvar *> &colvars,
: colvar_grid<size_t>(colvars, def_count, 1, margin) : colvar_grid<size_t>(colvars, def_count, 1, margin)
{} {}
std::string colvar_grid_count::get_state_params() const
{
return colvar_grid<size_t>::get_state_params();
}
int colvar_grid_count::parse_params(std::string const &conf,
colvarparse::Parse_Mode const parse_mode)
{
return colvar_grid<size_t>::parse_params(conf, parse_mode);
}
std::istream & colvar_grid_count::read_restart(std::istream &is)
{
return colvar_grid<size_t>::read_restart(is);
}
cvm::memory_stream & colvar_grid_count::read_restart(cvm::memory_stream &is)
{
return colvar_grid<size_t>::read_restart(is);
}
std::ostream & colvar_grid_count::write_restart(std::ostream &os)
{
return colvar_grid<size_t>::write_restart(os);
}
cvm::memory_stream & colvar_grid_count::write_restart(cvm::memory_stream &os)
{
return colvar_grid<size_t>::write_restart(os);
}
std::istream &colvar_grid_count::read_raw(std::istream &is)
{
return colvar_grid<size_t>::read_raw(is);
}
cvm::memory_stream &colvar_grid_count::read_raw(cvm::memory_stream &is)
{
return colvar_grid<size_t>::read_raw(is);
}
std::ostream &colvar_grid_count::write_raw(std::ostream &os, size_t const buf_size) const
{
return colvar_grid<size_t>::write_raw(os, buf_size);
}
cvm::memory_stream &colvar_grid_count::write_raw(cvm::memory_stream &os,
size_t const buf_size) const
{
return colvar_grid<size_t>::write_raw(os, buf_size);
}
std::istream & colvar_grid_count::read_multicol(std::istream &is, bool add) std::istream & colvar_grid_count::read_multicol(std::istream &is, bool add)
{ {
return colvar_grid<size_t>::read_multicol(is, add); return colvar_grid<size_t>::read_multicol(is, add);
@ -96,6 +146,58 @@ colvar_grid_scalar::~colvar_grid_scalar()
{ {
} }
std::string colvar_grid_scalar::get_state_params() const
{
return colvar_grid<cvm::real>::get_state_params();
}
int colvar_grid_scalar::parse_params(std::string const &conf,
colvarparse::Parse_Mode const parse_mode)
{
return colvar_grid<cvm::real>::parse_params(conf, parse_mode);
}
std::istream &colvar_grid_scalar::read_restart(std::istream &is)
{
return colvar_grid<cvm::real>::read_restart(is);
}
cvm::memory_stream &colvar_grid_scalar::read_restart(cvm::memory_stream &is)
{
return colvar_grid<cvm::real>::read_restart(is);
}
std::ostream &colvar_grid_scalar::write_restart(std::ostream &os)
{
return colvar_grid<cvm::real>::write_restart(os);
}
cvm::memory_stream &colvar_grid_scalar::write_restart(cvm::memory_stream &os)
{
return colvar_grid<cvm::real>::write_restart(os);
}
std::istream &colvar_grid_scalar::read_raw(std::istream &is)
{
return colvar_grid<cvm::real>::read_raw(is);
}
cvm::memory_stream &colvar_grid_scalar::read_raw(cvm::memory_stream &is)
{
return colvar_grid<cvm::real>::read_raw(is);
}
std::ostream &colvar_grid_scalar::write_raw(std::ostream &os, size_t const buf_size) const
{
return colvar_grid<cvm::real>::write_raw(os, buf_size);
}
cvm::memory_stream &colvar_grid_scalar::write_raw(cvm::memory_stream &os,
size_t const buf_size) const
{
return colvar_grid<cvm::real>::write_raw(os, buf_size);
}
std::istream & colvar_grid_scalar::read_multicol(std::istream &is, bool add) std::istream & colvar_grid_scalar::read_multicol(std::istream &is, bool add)
{ {
return colvar_grid<cvm::real>::read_multicol(is, add); return colvar_grid<cvm::real>::read_multicol(is, add);
@ -195,30 +297,63 @@ cvm::real colvar_grid_scalar::entropy() const
return bin_volume * sum; return bin_volume * sum;
} }
/// \brief Return the RMSD between this grid's data and another one
/// Grids must have the same dimensions.
cvm::real colvar_grid_scalar::grid_rmsd(colvar_grid_scalar const &other_grid) const
{
if (other_grid.data.size() != this->data.size()) {
cvm::error("Error: trying to subtract two grids with "
"different size.\n");
return -1.;
}
cvm::real sum2 = 0.0;
if (samples && other_grid.samples) {
for (size_t i = 0; i < data.size(); i++) {
size_t n = samples->get_value(i);
cvm::real us = n ? data[i] / n : 0.0;
n = other_grid.samples->get_value(i);
cvm::real them = n ? other_grid.data[i ] / n : 0.0;
cvm::real d = us - them;
sum2 += d*d;
}
} else {
for (size_t i = 0; i < data.size(); i++) {
cvm::real d = other_grid.data[i] - data[i];
sum2 += d*d;
}
}
return sqrt(sum2/this->data.size());
}
colvar_grid_gradient::colvar_grid_gradient() colvar_grid_gradient::colvar_grid_gradient()
: colvar_grid<cvm::real>(), : colvar_grid<cvm::real>(), samples(NULL), full_samples(0), min_samples(0)
samples(NULL),
weights(NULL)
{} {}
colvar_grid_gradient::colvar_grid_gradient(std::vector<int> const &nx_i) colvar_grid_gradient::colvar_grid_gradient(std::vector<int> const &nx_i)
: colvar_grid<cvm::real>(nx_i, 0.0, nx_i.size()), : colvar_grid<cvm::real>(nx_i, 0.0, nx_i.size()), samples(NULL), full_samples(0), min_samples(0)
samples(NULL),
weights(NULL)
{} {}
colvar_grid_gradient::colvar_grid_gradient(std::vector<colvar *> &colvars) colvar_grid_gradient::colvar_grid_gradient(std::vector<colvar *> &colvars)
: colvar_grid<cvm::real>(colvars, 0.0, colvars.size()), : colvar_grid<cvm::real>(colvars, 0.0, colvars.size()), samples(NULL), full_samples(0), min_samples(0)
samples(NULL),
weights(NULL)
{} {}
colvar_grid_gradient::colvar_grid_gradient(std::vector<colvar *> &colvars, std::shared_ptr<colvar_grid_count> samples_in)
: colvar_grid<cvm::real>(colvars, 0.0, colvars.size()), samples(samples_in), full_samples(0), min_samples(0)
{
samples_in->has_parent_data = true;
}
colvar_grid_gradient::colvar_grid_gradient(std::string &filename) colvar_grid_gradient::colvar_grid_gradient(std::string &filename)
: colvar_grid<cvm::real>(), : colvar_grid<cvm::real>(),
samples(NULL), samples(NULL)
weights(NULL)
{ {
std::istream &is = cvm::main()->proxy->input_stream(filename, std::istream &is = cvm::main()->proxy->input_stream(filename,
"gradient file"); "gradient file");
@ -280,6 +415,57 @@ colvar_grid_gradient::colvar_grid_gradient(std::string &filename)
cvm::main()->proxy->close_input_stream(filename); cvm::main()->proxy->close_input_stream(filename);
} }
std::string colvar_grid_gradient::get_state_params() const
{
return colvar_grid<cvm::real>::get_state_params();
}
int colvar_grid_gradient::parse_params(std::string const &conf,
colvarparse::Parse_Mode const parse_mode)
{
return colvar_grid<cvm::real>::parse_params(conf, parse_mode);
}
std::istream &colvar_grid_gradient::read_restart(std::istream &is)
{
return colvar_grid<cvm::real>::read_restart(is);
}
cvm::memory_stream &colvar_grid_gradient::read_restart(cvm::memory_stream &is)
{
return colvar_grid<cvm::real>::read_restart(is);
}
std::ostream &colvar_grid_gradient::write_restart(std::ostream &os)
{
return colvar_grid<cvm::real>::write_restart(os);
}
cvm::memory_stream &colvar_grid_gradient::write_restart(cvm::memory_stream &os)
{
return colvar_grid<cvm::real>::write_restart(os);
}
std::istream &colvar_grid_gradient::read_raw(std::istream &is)
{
return colvar_grid<cvm::real>::read_raw(is);
}
cvm::memory_stream &colvar_grid_gradient::read_raw(cvm::memory_stream &is)
{
return colvar_grid<cvm::real>::read_raw(is);
}
std::ostream &colvar_grid_gradient::write_raw(std::ostream &os, size_t const buf_size) const
{
return colvar_grid<cvm::real>::write_raw(os, buf_size);
}
cvm::memory_stream &colvar_grid_gradient::write_raw(cvm::memory_stream &os,
size_t const buf_size) const
{
return colvar_grid<cvm::real>::write_raw(os, buf_size);
}
std::istream & colvar_grid_gradient::read_multicol(std::istream &is, bool add) std::istream & colvar_grid_gradient::read_multicol(std::istream &is, bool add)
{ {
@ -371,9 +557,38 @@ void colvar_grid_gradient::write_1D_integral(std::ostream &os)
} }
/// \brief Return the RMSD between this grid's data and another one
/// Grids must have the same dimensions.
cvm::real colvar_grid_gradient::grid_rmsd(colvar_grid_gradient const &other_grid) const
{
if (other_grid.multiplicity() != this->multiplicity()) {
cvm::error("Error: trying to subtract two grids with "
"different multiplicity.\n");
return -1.;
}
integrate_potential::integrate_potential(std::vector<colvar *> &colvars, colvar_grid_gradient * gradients) if (other_grid.data.size() != this->data.size()) {
cvm::error("Error: trying to subtract two grids with "
"different size.\n");
return -1.;
}
cvm::real sum2 = 0.0;
std::vector<int> ix;
size_t imult;
for (ix = new_index(); index_ok(ix); incr(ix)) {
for (imult = 0; imult < this->multiplicity(); imult++) {
cvm::real d = this->value_output(ix, imult) - other_grid.value_output(ix, imult);
sum2 += d*d;
}
}
return sqrt(sum2/this->data.size());
}
integrate_potential::integrate_potential(std::vector<colvar *> &colvars, std::shared_ptr<colvar_grid_gradient> gradients)
: colvar_grid_scalar(colvars, true), : colvar_grid_scalar(colvars, true),
b_smoothed(false),
gradients(gradients) gradients(gradients)
{ {
// parent class colvar_grid_scalar is constructed with margin option set to true // parent class colvar_grid_scalar is constructed with margin option set to true
@ -402,8 +617,9 @@ integrate_potential::integrate_potential(std::vector<colvar *> &colvars, colvar_
} }
integrate_potential::integrate_potential(colvar_grid_gradient * gradients) integrate_potential::integrate_potential(std::shared_ptr<colvar_grid_gradient> gradients)
: gradients(gradients) : b_smoothed(false),
gradients(gradients)
{ {
nd = gradients->num_variables(); nd = gradients->num_variables();
nx = gradients->number_of_points_vec(); nx = gradients->number_of_points_vec();
@ -425,7 +641,7 @@ integrate_potential::integrate_potential(colvar_grid_gradient * gradients)
} }
int integrate_potential::integrate(const int itmax, const cvm::real &tol, cvm::real & err) int integrate_potential::integrate(const int itmax, const cvm::real &tol, cvm::real & err, bool verbose)
{ {
int iter = 0; int iter = 0;
@ -438,22 +654,24 @@ int integrate_potential::integrate(const int itmax, const cvm::real &tol, cvm::r
} else { } else {
corr = 0.0; corr = 0.0;
} }
std::vector<int> ix; std::vector<int> ix;
// Iterate over valid indices in gradient grid // Iterate over valid indices in gradient grid
for (ix = new_index(); gradients->index_ok(ix); incr(ix)) { for (ix = new_index(); gradients->index_ok(ix); incr(ix)) {
set_value(ix, sum); set_value(ix, sum);
sum += (gradients->value_output(ix) - corr) * widths[0]; cvm::real val = gradients->value_output_smoothed(ix, b_smoothed);
sum += (val - corr) * widths[0];
} }
if (index_ok(ix)) { if (index_ok(ix)) {
// This will happen if non-periodic: then PMF grid has one extra bin wrt gradient grid // This will happen if non-periodic: then PMF grid has one extra bin wrt gradient grid
// If not, sum should be zero
set_value(ix, sum); set_value(ix, sum);
} }
} else if (nd <= 3) { } else if (nd <= 3) {
nr_linbcg_sym(divergence, data, tol, itmax, iter, err); nr_linbcg_sym(divergence, data, tol, itmax, iter, err);
cvm::log("Integrated in " + cvm::to_str(iter) + " steps, error: " + cvm::to_str(err) + "\n"); if (verbose)
cvm::log("Integrated in " + cvm::to_str(iter) + " steps, error: " + cvm::to_str(err));
} else { } else {
cvm::error("Cannot integrate PMF in dimension > 3\n"); cvm::error("Cannot integrate PMF in dimension > 3\n");
@ -477,7 +695,7 @@ void integrate_potential::update_div_neighbors(const std::vector<int> &ix0)
std::vector<int> ix(ix0); std::vector<int> ix(ix0);
int i, j, k; int i, j, k;
// If not periodic, expanded grid ensures that neighbors of ix0 are valid grid points // If not periodic, expanded grid ensures that upper neighbors of ix0 are valid grid points
if (nd == 1) { if (nd == 1) {
return; return;
@ -509,30 +727,23 @@ void integrate_potential::update_div_neighbors(const std::vector<int> &ix0)
} }
} }
void integrate_potential::get_grad(cvm::real * g, std::vector<int> &ix) void integrate_potential::get_grad(cvm::real * g, std::vector<int> &ix)
{ {
size_t count, i; size_t i;
bool edge = gradients->wrap_edge(ix); // Detect edge if non-PBC bool edge = gradients->wrap_detect_edge(ix); // Detect edge if non-PBC
if (gradients->samples) { if (edge) {
count = gradients->samples->value(ix); for ( i = 0; i<nd; i++ ) {
} else { g[i] = 0.0;
count = 1; }
return;
} }
if (!edge && count) { gradients->vector_value_smoothed(ix, g, b_smoothed);
cvm::real const *grad = &(gradients->value(ix));
cvm::real const fact = 1.0 / count;
for ( i = 0; i<nd; i++ ) {
g[i] = fact * grad[i];
}
} else {
for ( i = 0; i<nd; i++ ) {
g[i] = 0.0;
}
}
} }
void integrate_potential::update_div_local(const std::vector<int> &ix0) void integrate_potential::update_div_local(const std::vector<int> &ix0)
{ {
const size_t linear_index = address(ix0); const size_t linear_index = address(ix0);

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,233 @@
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvar.h" #include "colvar.h"
#include "colvargrid.h" #include "colvargrid.h"
#include "colvars_memstream.h"
template <class T, class IST> IST &read_restart_template_(colvar_grid<T> &g, IST &is)
{
auto const start_pos = is.tellg();
std::string conf;
if ((is >> colvarparse::read_block("grid_parameters", &conf)) &&
(g.parse_params(conf, colvarparse::parse_restart) == COLVARS_OK) && g.read_raw(is)) {
return is;
}
auto const error_pos = is.tellg();
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
cvm::error("Error: in reading grid state from stream at position " + cvm::to_str(error_pos) +
"\n",
COLVARS_INPUT_ERROR);
return is;
}
template <class T> std::istream &colvar_grid<T>::read_restart(std::istream &is)
{
return read_restart_template_<T, std::istream>(*this, is);
}
template <class T> cvm::memory_stream &colvar_grid<T>::read_restart(cvm::memory_stream &is)
{
return read_restart_template_<T, cvm::memory_stream>(*this, is);
}
template <class T> std::ostream &colvar_grid<T>::write_restart(std::ostream &os)
{
os << "grid_parameters {\n" << get_state_params() << "}\n";
write_raw(os);
return os;
}
template <class T> cvm::memory_stream &colvar_grid<T>::write_restart(cvm::memory_stream &os)
{
os << std::string("grid_parameters") << get_state_params();
write_raw(os);
return os;
}
template <class T, class IST> IST &read_raw_template_(colvar_grid<T> &g, IST &is)
{
auto const start_pos = is.tellg();
for (std::vector<int> ix = g.new_index(); g.index_ok(ix); g.incr(ix)) {
for (size_t imult = 0; imult < g.mult; imult++) {
T new_value;
if (is >> new_value) {
g.value_input(ix, new_value, imult);
} else {
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
cvm::error(
"Error: failed to read all of the grid points from file. Possible explanations: grid "
"parameters in the configuration (lowerBoundary, upperBoundary, width) are different "
"from those in the file, or the file is corrupt/incomplete.\n",
COLVARS_INPUT_ERROR);
return is;
}
}
}
g.has_data = true;
return is;
}
template <class T> std::istream &colvar_grid<T>::read_raw(std::istream &is)
{
return read_raw_template_<T, std::istream>(*this, is);
}
template <class T> cvm::memory_stream &colvar_grid<T>::read_raw(cvm::memory_stream &is)
{
return read_raw_template_<T, cvm::memory_stream>(*this, is);
}
template <class T>
std::ostream &colvar_grid<T>::write_raw(std::ostream &os, size_t const buf_size) const
{
auto const w = os.width();
auto const p = os.precision();
size_t count = 0;
for (auto ix = new_index(); index_ok(ix); incr(ix)) {
for (size_t imult = 0; imult < mult; imult++) {
os << " " << std::setw(w) << std::setprecision(p) << value_output(ix, imult);
if (((++count) % buf_size) == 0)
os << "\n";
}
}
// write a final newline only if buffer is not empty
if ((count % buf_size) != 0)
os << "\n";
return os;
}
template <class T>
cvm::memory_stream &colvar_grid<T>::write_raw(cvm::memory_stream &os, size_t const buf_size) const
{
for (auto ix = new_index(); index_ok(ix); incr(ix)) {
for (size_t imult = 0; imult < mult; imult++) {
os << value_output(ix, imult);
}
}
return os;
}
template <class T> std::string colvar_grid<T>::get_state_params() const
{
std::ostringstream os;
size_t i;
os << " n_colvars " << nd << "\n";
os << " lower_boundaries ";
for (i = 0; i < nd; i++)
os << " " << lower_boundaries[i];
os << "\n";
os << " upper_boundaries ";
for (i = 0; i < nd; i++)
os << " " << upper_boundaries[i];
os << "\n";
os << " widths ";
for (i = 0; i < nd; i++)
os << " " << widths[i];
os << "\n";
os << " sizes ";
for (i = 0; i < nd; i++)
os << " " << nx[i];
os << "\n";
return os.str();
}
template <class T> int colvar_grid<T>::parse_params(std::string const &conf,
colvarparse::Parse_Mode const parse_mode)
{
if (cvm::debug())
cvm::log("Reading grid configuration from string.\n");
std::vector<int> old_nx = nx;
std::vector<colvarvalue> old_lb = lower_boundaries;
std::vector<colvarvalue> old_ub = upper_boundaries;
std::vector<cvm::real> old_w = widths;
{
size_t nd_in = 0;
// this is only used in state files
colvarparse::get_keyval(conf, "n_colvars", nd_in, nd, colvarparse::parse_silent);
if (nd_in != nd) {
cvm::error("Error: trying to read data for a grid "
"that contains a different number of colvars ("+
cvm::to_str(nd_in)+") than the grid defined "
"in the configuration file("+cvm::to_str(nd)+
").\n");
return COLVARS_ERROR;
}
}
// underscore keywords are used in state file
colvarparse::get_keyval(conf, "lower_boundaries",
lower_boundaries, lower_boundaries, colvarparse::parse_silent);
colvarparse::get_keyval(conf, "upper_boundaries",
upper_boundaries, upper_boundaries, colvarparse::parse_silent);
// camel case keywords are used in config file
colvarparse::get_keyval(conf, "lowerBoundaries",
lower_boundaries, lower_boundaries, parse_mode);
colvarparse::get_keyval(conf, "upperBoundaries",
upper_boundaries, upper_boundaries, parse_mode);
colvarparse::get_keyval(conf, "widths", widths, widths, parse_mode);
// only used in state file
colvarparse::get_keyval(conf, "sizes", nx, nx, colvarparse::parse_silent);
if (nd < lower_boundaries.size()) nd = lower_boundaries.size();
if (! use_actual_value.size()) use_actual_value.assign(nd, false);
if (! periodic.size()) periodic.assign(nd, false);
if (! widths.size()) widths.assign(nd, 1.0);
cvm::real eps = 1.e-10;
bool new_params = false;
if (old_nx.size()) {
for (size_t i = 0; i < nd; i++) {
if (old_nx[i] != nx[i] ||
cvm::sqrt(cv[i]->dist2(old_lb[i], lower_boundaries[i])) > eps ||
cvm::sqrt(cv[i]->dist2(old_ub[i], upper_boundaries[i])) > eps ||
cvm::fabs(old_w[i] - widths[i]) > eps) {
new_params = true;
}
}
} else {
new_params = true;
}
// reallocate the array in case the grid params have just changed
if (new_params) {
init_from_boundaries();
// data.clear(); // no longer needed: setup calls clear()
return this->setup(nx, T(), mult);
}
return COLVARS_OK;
}
template <class T> template <class T>
@ -90,6 +317,9 @@ std::istream & colvar_grid<T>::read_multicol(std::istream &is, bool add)
for (size_t i = 0; i < nd; i++ ) { for (size_t i = 0; i < nd; i++ ) {
if ( !(is >> x) ) end_of_file = true; if ( !(is >> x) ) end_of_file = true;
bin[i] = value_to_bin_scalar(x, i); bin[i] = value_to_bin_scalar(x, i);
// if x is out of bounds and we are using PBC, wrap it
// Ignore out of bounds points in non-PBC
wrap_detect_edge(bin);
} }
if (end_of_file) break; if (end_of_file) break;

View File

@ -7,13 +7,10 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <iostream>
#include <iomanip> #include <iomanip>
#include <sstream> #include <iostream>
#include <fstream> #include <memory>
#include <cstring>
#include <vector> #include <vector>
#include <map>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarparse.h" #include "colvarparse.h"
@ -21,6 +18,7 @@
#include "colvar.h" #include "colvar.h"
#include "colvarbias.h" #include "colvarbias.h"
#include "colvarbias_abf.h" #include "colvarbias_abf.h"
#include "colvarbias_abmd.h"
#include "colvarbias_alb.h" #include "colvarbias_alb.h"
#include "colvarbias_histogram.h" #include "colvarbias_histogram.h"
#include "colvarbias_histogram_reweight_amd.h" #include "colvarbias_histogram_reweight_amd.h"
@ -29,7 +27,7 @@
#include "colvarscript.h" #include "colvarscript.h"
#include "colvaratoms.h" #include "colvaratoms.h"
#include "colvarcomp.h" #include "colvarcomp.h"
#include "colvars_memstream.h"
/// Track usage of Colvars features /// Track usage of Colvars features
@ -69,6 +67,11 @@ protected:
}; };
namespace {
constexpr uint32_t colvars_magic_number = 2013813594;
}
colvarmodule::colvarmodule(colvarproxy *proxy_in) colvarmodule::colvarmodule(colvarproxy *proxy_in)
{ {
depth_s = 0; depth_s = 0;
@ -98,16 +101,14 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
version_int = proxy->get_version_from_string(COLVARS_VERSION); version_int = proxy->get_version_from_string(COLVARS_VERSION);
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::log("Initializing the collective variables module, version "+ cvm::log(
version()+".\n"); "Initializing the collective variables module, version " + version() +
(patch_version_number() ? (" (patch " + cvm::to_str(patch_version_number()) + ")") : "") +
".\n");
cvm::log("Please cite Fiorin et al, Mol Phys 2013:\n" cvm::log("Please cite Fiorin et al, Mol Phys 2013:\n"
" https://doi.org/10.1080/00268976.2013.813594\n" " https://doi.org/10.1080/00268976.2013.813594\n"
"as well as all other papers listed below for individual features used.\n"); "as well as all other papers listed below for individual features used.\n");
if (proxy->smp_enabled() == COLVARS_OK) {
cvm::log("SMP parallelism is enabled; if needed, use \"smp off\" to override this.\n");
}
#if (__cplusplus >= 201103L) #if (__cplusplus >= 201103L)
cvm::log("This version was built with the C++11 standard or higher.\n"); cvm::log("This version was built with the C++11 standard or higher.\n");
#else #else
@ -116,8 +117,38 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
" https://colvars.github.io/README-c++11.html\n"); " https://colvars.github.io/README-c++11.html\n");
#endif #endif
cvm::log("Summary of compile-time features available in this build:\n");
if (proxy->check_smp_enabled() == COLVARS_NOT_IMPLEMENTED) {
cvm::log(" - SMP parallelism: not available\n");
} else {
if (proxy->check_smp_enabled() == COLVARS_OK) {
cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n");
} else {
cvm::log(" - SMP parallelism: available, but not enabled\n");
}
}
#if defined(LEPTON)
cvm::log(" - Lepton custom functions: available\n");
#else
cvm::log(" - Lepton custom functions: not available\n");
#endif
#if defined(COLVARS_TCL)
cvm::log(" - Tcl interpreter: available\n");
#else
cvm::log(" - Tcl interpreter: not available\n");
#endif
// set initial default values // set initial default values
binary_restart = false;
char const *env_var = getenv("COLVARS_BINARY_RESTART");
if (env_var && atoi(env_var)) {
binary_restart = true;
}
// "it_restart" will be set by the input state file, if any; // "it_restart" will be set by the input state file, if any;
// "it" should be updated by the proxy // "it" should be updated by the proxy
colvarmodule::it = colvarmodule::it_restart = 0; colvarmodule::it = colvarmodule::it_restart = 0;
@ -182,6 +213,13 @@ size_t colvarmodule::size() const
} }
void colvarmodule::set_initial_step(step_number it_in)
{
cvm::log("Setting initial step number from MD engine: " + cvm::to_str(it_in) + "\n");
it = it_restart = it_in;
}
int colvarmodule::read_config_file(char const *config_filename) int colvarmodule::read_config_file(char const *config_filename)
{ {
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
@ -327,6 +365,7 @@ void colvarmodule::config_changed()
int colvarmodule::parse_global_params(std::string const &conf) int colvarmodule::parse_global_params(std::string const &conf)
{ {
int error_code = COLVARS_OK;
// TODO document and then echo this keyword // TODO document and then echo this keyword
parse->get_keyval(conf, "logLevel", log_level_, log_level_, parse->get_keyval(conf, "logLevel", log_level_, log_level_,
colvarparse::parse_silent); colvarparse::parse_silent);
@ -334,10 +373,7 @@ int colvarmodule::parse_global_params(std::string const &conf)
std::string units; std::string units;
if (parse->get_keyval(conf, "units", units)) { if (parse->get_keyval(conf, "units", units)) {
units = colvarparse::to_lower_cppstr(units); units = colvarparse::to_lower_cppstr(units);
int error_code = proxy->set_unit_system(units, (colvars.size() != 0)); error_code |= proxy->set_unit_system(units, (colvars.size() != 0));
if (error_code != COLVARS_OK) {
return error_code;
}
} }
} }
@ -346,7 +382,7 @@ int colvarmodule::parse_global_params(std::string const &conf)
size_t pos = 0; size_t pos = 0;
while (parse->key_lookup(conf, "indexFile", &index_file_name, &pos)) { while (parse->key_lookup(conf, "indexFile", &index_file_name, &pos)) {
cvm::log("# indexFile = \""+index_file_name+"\"\n"); cvm::log("# indexFile = \""+index_file_name+"\"\n");
read_index_file(index_file_name.c_str()); error_code |= read_index_file(index_file_name.c_str());
index_file_name.clear(); index_file_name.clear();
} }
} }
@ -358,9 +394,8 @@ int colvarmodule::parse_global_params(std::string const &conf)
} }
bool b_analysis = true; bool b_analysis = true;
if (parse->get_keyval(conf, "analysis", b_analysis, true, if (parse->get_keyval(conf, "analysis", b_analysis, true, colvarparse::parse_silent)) {
colvarparse::parse_silent)) { cvm::log("Warning: keyword \"analysis\" is deprecated: it is now always set "
cvm::log("Warning: keyword \"analysis\" is deprecated: it is now set "
"to true; individual analyses are performed only if requested."); "to true; individual analyses are performed only if requested.");
} }
@ -391,7 +426,12 @@ int colvarmodule::parse_global_params(std::string const &conf)
parse->get_keyval(conf, "sourceTclFile", source_Tcl_script); parse->get_keyval(conf, "sourceTclFile", source_Tcl_script);
#endif #endif
return cvm::get_error(); if (proxy->engine_name() == "GROMACS" && proxy->version_number() >= 20231003) {
parse->get_keyval(conf, "defaultInputStateFile", default_input_state_file_,
default_input_state_file_);
}
return error_code;
} }
@ -522,6 +562,9 @@ int colvarmodule::parse_biases(std::string const &conf)
/// initialize ABF instances /// initialize ABF instances
parse_biases_type<colvarbias_abf>(conf, "abf"); parse_biases_type<colvarbias_abf>(conf, "abf");
/// initialize ABMD instances
parse_biases_type<colvarbias_abmd>(conf, "abmd");
/// initialize adaptive linear biases /// initialize adaptive linear biases
parse_biases_type<colvarbias_alb>(conf, "ALB"); parse_biases_type<colvarbias_alb>(conf, "ALB");
@ -791,28 +834,26 @@ int colvarmodule::calc()
// write restart files and similar data // write restart files and similar data
if (restart_out_freq && (cvm::step_relative() > 0) && if (restart_out_freq && (cvm::step_relative() > 0) &&
((cvm::step_absolute() % restart_out_freq) == 0) ) { ((cvm::step_absolute() % restart_out_freq) == 0)) {
if (restart_out_name.size()) { if (restart_out_name.size()) {
// Write restart file, if different from main output // Write restart file, if different from main output
error_code |= write_restart_file(restart_out_name); error_code |= write_restart_file(restart_out_name);
} else { } else if (output_prefix().size()) {
error_code |= write_restart_file(output_prefix()+".colvars.state"); error_code |= write_restart_file(output_prefix() + ".colvars.state");
} }
cvm::increase_depth(); if (output_prefix().size()) {
for (std::vector<colvar *>::iterator cvi = colvars.begin(); cvm::increase_depth();
cvi != colvars.end(); for (std::vector<colvar *>::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) {
cvi++) { // TODO remove this when corrFunc becomes a bias
// TODO remove this when corrFunc becomes a bias error_code |= (*cvi)->write_output_files();
error_code |= (*cvi)->write_output_files(); }
for (std::vector<colvarbias *>::iterator bi = biases.begin(); bi != biases.end(); bi++) {
error_code |= (*bi)->write_state_to_replicas();
}
cvm::decrease_depth();
} }
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
error_code |= (*bi)->write_state_to_replicas();
}
cvm::decrease_depth();
} }
// Write output files for biases, at the specified frequency for each // Write output files for biases, at the specified frequency for each
@ -881,7 +922,7 @@ int colvarmodule::calc_colvars()
} }
// if SMP support is available, split up the work // if SMP support is available, split up the work
if (proxy->smp_enabled() == COLVARS_OK) { if (proxy->check_smp_enabled() == COLVARS_OK) {
// first, calculate how much work (currently, how many active CVCs) each colvar has // first, calculate how much work (currently, how many active CVCs) each colvar has
@ -963,8 +1004,16 @@ int colvarmodule::calc_biases()
} }
} }
// if SMP support is available, split up the work bool biases_need_main_thread = false;
if (proxy->smp_enabled() == COLVARS_OK) { for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
if ((*bi)->replica_share_freq() > 0) {
// Biases that share data with replicas need read/write access to I/O or MPI
biases_need_main_thread = true;
}
}
// If SMP support is available, split up the work (unless biases need to use main thread's memory)
if (proxy->check_smp_enabled() == COLVARS_OK && !biases_need_main_thread) {
if (use_scripted_forces && !scripting_after_biases) { if (use_scripted_forces && !scripting_after_biases) {
// calculate biases and scripted forces in parallel // calculate biases and scripted forces in parallel
@ -980,10 +1029,12 @@ int colvarmodule::calc_biases()
error_code |= calc_scripted_forces(); error_code |= calc_scripted_forces();
} }
// Straight loop over biases on a single thread
cvm::increase_depth(); cvm::increase_depth();
for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) { for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
error_code |= (*bi)->update(); error_code |= (*bi)->update();
if (cvm::get_error()) { if (cvm::get_error()) {
cvm::decrease_depth();
return error_code; return error_code;
} }
} }
@ -994,7 +1045,7 @@ int colvarmodule::calc_biases()
total_bias_energy += (*bi)->get_energy(); total_bias_energy += (*bi)->get_energy();
} }
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); return error_code;
} }
@ -1082,9 +1133,22 @@ int colvarmodule::write_restart_file(std::string const &out_name)
cvm::log("Saving collective variables state to \""+out_name+"\".\n"); cvm::log("Saving collective variables state to \""+out_name+"\".\n");
std::ostream &restart_out_os = proxy->output_stream(out_name, "state file"); std::ostream &restart_out_os = proxy->output_stream(out_name, "state file");
if (!restart_out_os) return COLVARS_FILE_ERROR; if (!restart_out_os) return COLVARS_FILE_ERROR;
if (!write_restart(restart_out_os)) {
return cvm::error("Error: in writing restart file.\n", COLVARS_FILE_ERROR); if (binary_restart) {
cvm::memory_stream mem_os;
if (!write_state(mem_os)) {
return cvm::error("Error: in writing binary state information to file.\n", COLVARS_ERROR);
}
if (!restart_out_os.write(reinterpret_cast<char *>(mem_os.output_buffer()),
mem_os.length())) {
return cvm::error("Error: in writing restart file.\n", COLVARS_FILE_ERROR);
}
} else {
if (!write_state(restart_out_os)) {
return cvm::error("Error: in writing restart file.\n", COLVARS_FILE_ERROR);
}
} }
proxy->close_output_stream(out_name); proxy->close_output_stream(out_name);
// Take the opportunity to flush colvars.traj // Take the opportunity to flush colvars.traj
@ -1097,7 +1161,7 @@ int colvarmodule::write_restart_string(std::string &output)
{ {
cvm::log("Saving state to output buffer.\n"); cvm::log("Saving state to output buffer.\n");
std::ostringstream os; std::ostringstream os;
if (!write_restart(os)) { if (!write_state(os)) {
return cvm::error("Error: in writing restart to buffer.\n", COLVARS_FILE_ERROR); return cvm::error("Error: in writing restart to buffer.\n", COLVARS_FILE_ERROR);
} }
output = os.str(); output = os.str();
@ -1207,9 +1271,17 @@ int colvarmodule::end_of_step()
int colvarmodule::update_engine_parameters() int colvarmodule::update_engine_parameters()
{ {
if (this->size() == 0) return cvm::get_error(); if (size() == 0) {
for (std::vector<colvar *>::iterator cvi = variables()->begin(); // No-op if no variables or biases are defined
cvi != variables()->end(); cvi++) { return cvm::get_error();
}
if (proxy->simulation_running()) {
cvm::log("Current simulation parameters: initial step = " + cvm::to_str(it) +
", integration timestep = " + cvm::to_str(dt()) + "\n");
}
cvm::log("Updating atomic parameters (masses, charges, etc).\n");
for (std::vector<colvar *>::iterator cvi = variables()->begin(); cvi != variables()->end();
cvi++) {
(*cvi)->setup(); (*cvi)->setup();
} }
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
@ -1250,10 +1322,10 @@ int colvarmodule::reset()
parse->clear(); parse->clear();
// Iterate backwards because we are deleting the elements as we go // Iterate backwards because we are deleting the elements as we go
for (std::vector<colvarbias *>::reverse_iterator bi = biases.rbegin(); while (!biases.empty()) {
bi != biases.rend(); colvarbias* tail = biases.back();
bi++) { biases.pop_back();
delete *bi; // the bias destructor updates the biases array delete tail; // the bias destructor updates the biases array
} }
biases.clear(); biases.clear();
biases_active_.clear(); biases_active_.clear();
@ -1262,11 +1334,11 @@ int colvarmodule::reset()
reinterpret_cast<std::map<std::string, int> *>(num_biases_types_used_)->clear(); reinterpret_cast<std::map<std::string, int> *>(num_biases_types_used_)->clear();
// Iterate backwards because we are deleting the elements as we go // Iterate backwards because we are deleting the elements as we go
for (std::vector<colvar *>::reverse_iterator cvi = colvars.rbegin(); while (!colvars.empty()) {
cvi != colvars.rend(); colvar* cvi = colvars.back();
cvi++) { colvars.pop_back();
delete *cvi; // the colvar destructor updates the colvars array delete cvi; // the colvar destructor updates the colvars array
} };
colvars.clear(); colvars.clear();
reset_index_groups(); reset_index_groups();
@ -1274,64 +1346,119 @@ int colvarmodule::reset()
proxy->flush_output_streams(); proxy->flush_output_streams();
proxy->reset(); proxy->reset();
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); clear_error();
return COLVARS_OK;
} }
int colvarmodule::setup_input() int colvarmodule::setup_input()
{ {
if (proxy->input_prefix().size()) { if (proxy->input_prefix().empty() && (!proxy->input_stream_exists("input state string")) &&
// Read a state file input_state_buffer_.empty()) {
std::string restart_in_name(proxy->input_prefix()+ // If no input sources have been defined up to this point, use defaultInputStateFile
std::string(".colvars.state")); proxy->set_input_prefix(default_input_state_file_);
std::istream *input_is = &(proxy->input_stream(restart_in_name, }
"restart file/channel",
false)); if (!proxy->input_prefix().empty()) {
// Read state from a file
std::string restart_in_name(proxy->input_prefix() + std::string(".colvars.state"));
std::istream *input_is = &(proxy->input_stream(restart_in_name, "restart file/channel", false));
if (!*input_is) { if (!*input_is) {
// Try without the suffix ".colvars.state" // Try without the suffix ".colvars.state"
restart_in_name = proxy->input_prefix(); restart_in_name = proxy->input_prefix();
input_is = &(proxy->input_stream(restart_in_name, input_is = &(proxy->input_stream(restart_in_name, "restart file/channel"));
"restart file/channel"));
if (!*input_is) { if (!*input_is) {
// Error message has already been printed, return now
return COLVARS_FILE_ERROR; return COLVARS_FILE_ERROR;
} }
} }
// Now that the file has been opened, clear this field so that this // Now that the file has been opened, clear this field so that this block
// function will not be called twice // will not be executed twice
proxy->input_prefix().clear(); proxy->set_input_prefix("");
cvm::log(cvm::line_marker);
cvm::log("Loading state from file \""+restart_in_name+"\".\n");
read_restart(*input_is);
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
proxy->close_input_stream(restart_in_name); input_is->seekg(0, std::ios::end);
size_t const file_size = input_is->tellg();
input_is->seekg(0, std::ios::beg);
return cvm::get_error(); bool binary_state_file = false;
}
// TODO This could soon be redundant uint32_t file_magic_number = 0;
if (proxy->input_buffer() != NULL) { if (file_size > sizeof(uint32_t)) {
// Read a string buffer if (input_is->read(reinterpret_cast<char *>(&file_magic_number), sizeof(uint32_t))) {
char const *buffer = proxy->input_buffer(); if (file_magic_number == colvars_magic_number) {
size_t const buffer_size = strlen(proxy->input_buffer()); binary_state_file = true;
// Clear proxy pointer for the next round }
proxy->input_buffer() = NULL; input_is->seekg(0, std::ios::beg);
if (buffer_size > 0) { }
std::istringstream input_is;
// Replace the buffer of input_is; work around the lack of const in
// pubsetbuf's prototype (which also needs to support output streams)
input_is.rdbuf()->pubsetbuf(const_cast<char *>(buffer), buffer_size);
cvm::log(cvm::line_marker);
cvm::log("Loading state from input buffer.\n");
read_restart(input_is);
cvm::log(cvm::line_marker);
return cvm::get_error();
} }
if (binary_state_file) {
cvm::log("Loading state from binary file \"" + restart_in_name + "\".\n");
// TODO integrate istream.read() into memory_stream to avoid copying
auto *buf = new unsigned char[file_size];
if (input_is->read(reinterpret_cast<char *>(buf), file_size)) {
cvm::memory_stream mem_is(file_size, buf);
if (!read_state(mem_is)) {
input_is->setstate(std::ios::failbit);
cvm::error("Error: cannot interpret contents of binary file \"" + restart_in_name +
"\".\n",
COLVARS_INPUT_ERROR);
}
} else {
cvm::error("Error: cannot read from binary file \"" + restart_in_name + "\".\n",
COLVARS_INPUT_ERROR);
}
delete[] buf;
} else {
cvm::log("Loading state from text file \"" + restart_in_name + "\".\n");
read_state(*input_is);
}
cvm::log(cvm::line_marker);
// Now that an explicit state file was read, we shall ignore any other restart info
if (proxy->input_stream_exists("input state string")) {
proxy->delete_input_stream("input state string");
}
input_state_buffer_.clear();
proxy->delete_input_stream(restart_in_name);
} }
return COLVARS_OK; if (proxy->input_stream_exists("input state string")) {
if (!input_state_buffer_.empty()) {
return cvm::error("Error: formatted/text and unformatted/binary input state buffers are "
"defined at the same time.\n",
COLVARS_BUG_ERROR);
}
cvm::log(cvm::line_marker);
cvm::log("Loading state from formatted string.\n");
read_state(proxy->input_stream("input state string"));
cvm::log(cvm::line_marker);
proxy->delete_input_stream("input state string");
}
if (!input_state_buffer_.empty()) {
cvm::log(cvm::line_marker);
cvm::log("Loading state from unformatted memory.\n");
cvm::memory_stream ms(input_state_buffer_.size(), input_state_buffer_.data());
read_state(ms);
cvm::log(cvm::line_marker);
input_state_buffer_.clear();
}
default_input_state_file_.clear();
return get_error();
} }
@ -1344,36 +1471,39 @@ int colvarmodule::setup_output()
std::string(proxy->restart_output_prefix()+".colvars.state") : std::string(proxy->restart_output_prefix()+".colvars.state") :
std::string(""); std::string("");
std::string const state_file_format(binary_restart ? " (binary format)" : "");
if (restart_out_name.size()) { if (restart_out_name.size()) {
cvm::log("The restart output state file will be \""+ cvm::log("The restart output state file" + state_file_format + " will be \""+
restart_out_name+"\".\n"); restart_out_name+"\".\n");
} }
output_prefix() = proxy->output_prefix(); if (output_prefix() != proxy->output_prefix()) {
if (output_prefix().size()) { output_prefix() = proxy->output_prefix();
cvm::log("The final output state file will be \""+ if (output_prefix().size()) {
(output_prefix().size() ? cvm::log("The final output state file will be \"" +
std::string(output_prefix()+".colvars.state") : (output_prefix().size() ? std::string(output_prefix() + ".colvars.state")
std::string("colvars.state"))+"\".\n"); : std::string("colvars.state")) +
// cvm::log (cvm::line_marker); "\".\n");
}
if (proxy->output_stream_exists(cv_traj_name)) {
// Close old file
proxy->close_output_stream(cv_traj_name);
cv_traj_write_labels = true;
}
cv_traj_name =
(output_prefix().size() ? std::string(output_prefix() + ".colvars.traj") : std::string(""));
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
error_code |= (*bi)->setup_output();
}
} }
cv_traj_name = return error_code;
(output_prefix().size() ?
std::string(output_prefix()+".colvars.traj") :
std::string(""));
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
error_code |= (*bi)->setup_output();
}
if (error_code != COLVARS_OK || cvm::get_error()) {
set_error_bits(COLVARS_FILE_ERROR);
}
return cvm::get_error();
} }
@ -1390,8 +1520,7 @@ std::string colvarmodule::state_file_prefix(char const *filename)
} }
template <typename IST> IST & colvarmodule::read_state_template_(IST &is)
std::istream & colvarmodule::read_restart(std::istream &is)
{ {
bool warn_total_forces = false; bool warn_total_forces = false;
@ -1417,8 +1546,11 @@ std::istream & colvarmodule::read_restart(std::istream &is)
} }
if (restart_version() != version()) { if (restart_version() != version()) {
cvm::log("This state file was generated with version "+ cvm::log("This state file was generated with version " + restart_version() + "\n");
restart_version()+"\n"); if (std::is_same<IST, cvm::memory_stream>::value) {
cvm::log("Warning: compatibility between differetn Colvars versions is not "
"guaranteed for unformatted (binary) state files.\n");
}
} }
if (restart_version_number() < 20160810) { if (restart_version_number() < 20160810) {
@ -1453,35 +1585,73 @@ std::istream & colvarmodule::read_restart(std::istream &is)
} }
std::istream & colvarmodule::read_state(std::istream &is)
{
return read_state_template_<std::istream>(is);
}
cvm::memory_stream &colvarmodule::read_state(cvm::memory_stream &is)
{
uint32_t file_magic_number = 0;
if (!(is >> file_magic_number)) {
return is;
}
if (file_magic_number == colvars_magic_number) {
return read_state_template_<cvm::memory_stream>(is);
} else {
is.setstate(std::ios::failbit);
cvm::error("Error: magic number of binary file (" +
cvm::to_str(static_cast<size_t>(file_magic_number)) +
") does not match the expected magic number for a Colvars state file (" +
cvm::to_str(static_cast<size_t>(colvars_magic_number)) + ").\n",
COLVARS_INPUT_ERROR);
}
return is;
}
int colvarmodule::set_input_state_buffer(size_t n, unsigned char *buf)
{
input_state_buffer_.clear();
std::copy(buf, buf + n, std::back_inserter(input_state_buffer_));
return COLVARS_OK;
}
int colvarmodule::set_input_state_buffer(std::vector<unsigned char> &buf)
{
input_state_buffer_ = std::move(buf);
return COLVARS_OK;
}
std::istream & colvarmodule::read_objects_state(std::istream &is) std::istream & colvarmodule::read_objects_state(std::istream &is)
{ {
std::streampos pos = 0; auto pos = is.tellg();
std::string word; std::string word;
while (is.good()) { while (is) {
pos = is.tellg(); pos = is.tellg();
word.clear();
is >> word;
if (word.size()) { if (is >> word) {
is.seekg(pos, std::ios::beg); is.seekg(pos);
if (word == "colvar") { if (word == "colvar") {
cvm::increase_depth(); cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin(); for (std::vector<colvar *>::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) {
cvi != colvars.end(); if (!((*cvi)->read_state(is))) {
cvi++) {
if ( !((*cvi)->read_state(is)) ) {
// Here an error signals that the variable is a match, but the // Here an error signals that the variable is a match, but the
// state is corrupt; otherwise, the variable rewinds is silently // state is corrupt; otherwise, the variable rewinds is silently
cvm::error("Error: in reading restart configuration for " cvm::error("Error: in reading state for collective variable \"" +
"collective variable \""+(*cvi)->name+"\".\n", (*cvi)->name + "\" at position " + cvm::to_str(is.tellg()) +
" in stream.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (is.tellg() > pos) break; // found it if (is.tellg() > pos)
break; // found it
} }
cvm::decrease_depth(); cvm::decrease_depth();
@ -1498,11 +1668,12 @@ std::istream & colvarmodule::read_objects_state(std::istream &is)
} }
if (!((*bi)->read_state(is))) { if (!((*bi)->read_state(is))) {
// Same as above, an error means a match but the state is incorrect // Same as above, an error means a match but the state is incorrect
cvm::error("Error: in reading restart configuration for bias \""+ cvm::error("Error: in reading state for bias \"" + (*bi)->name + "\" at position " +
(*bi)->name+"\".\n", cvm::to_str(is.tellg()) + " in stream.\n",
COLVARS_INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (is.tellg() > pos) break; // found it if (is.tellg() > pos)
break; // found it
} }
cvm::decrease_depth(); cvm::decrease_depth();
} }
@ -1521,6 +1692,25 @@ std::istream & colvarmodule::read_objects_state(std::istream &is)
} }
cvm::memory_stream &colvarmodule::read_objects_state(cvm::memory_stream &is)
{
// An unformatted stream must match the objects' exact configuration
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) {
if (!(*cvi)->read_state(is)) {
return is;
}
}
for (std::vector<colvarbias *>::iterator bi = biases.begin(); bi != biases.end(); bi++) {
if (!(*bi)->read_state(is)) {
return is;
}
}
cvm::decrease_depth();
return is;
}
int colvarmodule::print_total_forces_errning(bool warn_total_forces) int colvarmodule::print_total_forces_errning(bool warn_total_forces)
{ {
if (warn_total_forces) { if (warn_total_forces) {
@ -1643,18 +1833,24 @@ int colvarmodule::read_traj(char const *traj_filename,
} }
std::ostream & colvarmodule::write_restart(std::ostream &os) template <typename OST> OST &colvarmodule::write_state_template_(OST &os)
{ {
os.setf(std::ios::scientific, std::ios::floatfield); bool const formatted = !std::is_same<OST, cvm::memory_stream>::value;
os << "configuration {\n"
<< " step " << std::setw(it_width) std::ostringstream oss;
<< it << "\n" oss.setf(std::ios::scientific, std::ios::floatfield);
<< " dt " << dt() << "\n" oss << " step " << std::setw(it_width)
<< " version " << std::string(COLVARS_VERSION) << "\n"; << it << "\n"
<< " dt " << dt() << "\n"
<< " version " << std::string(COLVARS_VERSION) << "\n";
if (proxy->units.size() > 0) { if (proxy->units.size() > 0) {
os << " units " << proxy->units << "\n"; oss << " units " << proxy->units << "\n";
} }
os << "}\n\n";
os << std::string("configuration");
if (formatted) os << " {\n";
os << oss.str();
if (formatted) os << "}\n\n";
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -1681,7 +1877,32 @@ std::ostream & colvarmodule::write_restart(std::ostream &os)
} }
std::ostream & colvarmodule::write_traj_label(std::ostream &os) std::ostream &colvarmodule::write_state(std::ostream &os)
{
return write_state_template_<std::ostream>(os);
}
cvm::memory_stream &colvarmodule::write_state(cvm::memory_stream &os)
{
if (os << colvars_magic_number) {
write_state_template_<cvm::memory_stream>(os);
}
return os;
}
int colvarmodule::write_state_buffer(std::vector<unsigned char> &buffer)
{
cvm::memory_stream os(buffer);
if (os << colvars_magic_number) {
write_state_template_<cvm::memory_stream>(os);
}
return os ? COLVARS_OK : COLVARS_ERROR;
}
std::ostream &colvarmodule::write_traj_label(std::ostream &os)
{ {
os.setf(std::ios::scientific, std::ios::floatfield); os.setf(std::ios::scientific, std::ios::floatfield);
@ -1765,7 +1986,7 @@ size_t & colvarmodule::depth()
{ {
// NOTE: do not call log() or error() here, to avoid recursion // NOTE: do not call log() or error() here, to avoid recursion
colvarmodule *cv = cvm::main(); colvarmodule *cv = cvm::main();
if (proxy->smp_enabled() == COLVARS_OK) { if (proxy->check_smp_enabled() == COLVARS_OK) {
int const nt = proxy->smp_num_threads(); int const nt = proxy->smp_num_threads();
if (int(cv->depth_v.size()) != nt) { if (int(cv->depth_v.size()) != nt) {
proxy->smp_lock(); proxy->smp_lock();
@ -1810,7 +2031,7 @@ void colvarmodule::clear_error()
int colvarmodule::error(std::string const &message, int code) int colvarmodule::error(std::string const &message, int code)
{ {
set_error_bits(code); set_error_bits(code >= 0 ? code : COLVARS_ERROR);
std::string const trailing_newline = (message.size() > 0) ? std::string const trailing_newline = (message.size() > 0) ?
(message[message.size()-1] == '\n' ? "" : "\n") : ""; (message[message.size()-1] == '\n' ? "" : "\n") : "";
@ -1930,15 +2151,6 @@ int colvarmodule::reset_index_groups()
} }
int cvm::load_atoms(char const *file_name,
cvm::atom_group &atoms,
std::string const &pdb_field,
double pdb_field_value)
{
return proxy->load_atoms(file_name, atoms, pdb_field, pdb_field_value);
}
int cvm::load_coords(char const *file_name, int cvm::load_coords(char const *file_name,
std::vector<cvm::rvector> *pos, std::vector<cvm::rvector> *pos,
cvm::atom_group *atoms, cvm::atom_group *atoms,
@ -1953,7 +2165,7 @@ int cvm::load_coords(char const *file_name,
atoms->create_sorted_ids(); atoms->create_sorted_ids();
std::vector<cvm::rvector> sorted_pos(atoms->size(), cvm::rvector(0.0)); std::vector<cvm::atom_pos> sorted_pos(atoms->size(), cvm::rvector(0.0));
// Differentiate between PDB and XYZ files // Differentiate between PDB and XYZ files
if (colvarparse::to_lower_cppstr(ext) == std::string(".xyz")) { if (colvarparse::to_lower_cppstr(ext) == std::string(".xyz")) {
@ -1965,11 +2177,12 @@ int cvm::load_coords(char const *file_name,
error_code |= cvm::main()->load_coords_xyz(file_name, &sorted_pos, atoms); error_code |= cvm::main()->load_coords_xyz(file_name, &sorted_pos, atoms);
} else { } else {
// Otherwise, call proxy function for PDB // Otherwise, call proxy function for PDB
error_code |= proxy->load_coords(file_name, error_code |= proxy->load_coords_pdb(file_name, sorted_pos, atoms->sorted_ids(), pdb_field,
sorted_pos, atoms->sorted_ids(), pdb_field_value);
pdb_field, pdb_field_value);
} }
if (error_code != COLVARS_OK) return error_code;
std::vector<int> const &map = atoms->sorted_ids_map(); std::vector<int> const &map = atoms->sorted_ids_map();
for (size_t i = 0; i < atoms->size(); i++) { for (size_t i = 0; i < atoms->size(); i++) {
(*pos)[map[i]] = sorted_pos[i]; (*pos)[map[i]] = sorted_pos[i];
@ -1985,7 +2198,7 @@ int cvm::load_coords_xyz(char const *filename,
bool keep_open) bool keep_open)
{ {
std::istream &xyz_is = proxy->input_stream(filename, "XYZ file"); std::istream &xyz_is = proxy->input_stream(filename, "XYZ file");
unsigned int natoms; size_t natoms;
char symbol[256]; char symbol[256];
std::string line; std::string line;
cvm::real x = 0.0, y = 0.0, z = 0.0; cvm::real x = 0.0, y = 0.0, z = 0.0;
@ -2009,12 +2222,19 @@ int cvm::load_coords_xyz(char const *filename,
cvm::getline(xyz_is, line); cvm::getline(xyz_is, line);
xyz_is.width(255); xyz_is.width(255);
} else { } else {
proxy->close_input_stream(filename);
return cvm::error(error_msg, COLVARS_INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
if (pos->size() > natoms) {
proxy->close_input_stream(filename);
return cvm::error("File \"" + std::string(filename) + "\" contains fewer atoms (" + cvm::to_str(natoms)
+ ") than expected (" + cvm::to_str(pos->size()) + ").", COLVARS_INPUT_ERROR);
}
std::vector<atom_pos>::iterator pos_i = pos->begin(); std::vector<atom_pos>::iterator pos_i = pos->begin();
size_t xyz_natoms = 0; size_t xyz_natoms = 0;
if (pos->size() != natoms) { // Use specified indices if (pos->size() < natoms) { // Use specified indices
int next = 0; // indices are zero-based int next = 0; // indices are zero-based
if (!atoms) { if (!atoms) {
// In the other branch of this test, reading all positions from the file, // In the other branch of this test, reading all positions from the file,
@ -2022,6 +2242,13 @@ int cvm::load_coords_xyz(char const *filename,
return cvm::error("Trying to read partial positions with invalid atom group pointer", return cvm::error("Trying to read partial positions with invalid atom group pointer",
COLVARS_BUG_ERROR); COLVARS_BUG_ERROR);
} }
if (static_cast<unsigned int>(atoms->sorted_ids().back()) > natoms) {
proxy->close_input_stream(filename);
return cvm::error("File \"" + std::string(filename) + "\" contains fewer atoms (" + cvm::to_str(natoms)
+ ") than expected (" + cvm::to_str(atoms->sorted_ids().back()) + ").", COLVARS_INPUT_ERROR);
}
std::vector<int>::const_iterator index = atoms->sorted_ids().begin(); std::vector<int>::const_iterator index = atoms->sorted_ids().begin();
for ( ; pos_i != pos->end() ; pos_i++, index++) { for ( ; pos_i != pos->end() ; pos_i++, index++) {
@ -2038,6 +2265,7 @@ int cvm::load_coords_xyz(char const *filename,
(*pos_i)[2] = proxy->angstrom_to_internal(z); (*pos_i)[2] = proxy->angstrom_to_internal(z);
xyz_natoms++; xyz_natoms++;
} else { } else {
proxy->close_input_stream(filename);
return cvm::error(error_msg, COLVARS_INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
} }
@ -2053,12 +2281,14 @@ int cvm::load_coords_xyz(char const *filename,
(*pos_i)[2] = proxy->angstrom_to_internal(z); (*pos_i)[2] = proxy->angstrom_to_internal(z);
xyz_natoms++; xyz_natoms++;
} else { } else {
proxy->close_input_stream(filename);
return cvm::error(error_msg, COLVARS_INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
} }
} }
if (xyz_natoms != pos->size()) { if (xyz_natoms != pos->size()) {
proxy->close_input_stream(filename);
return cvm::error("Error: The number of positions read from file \""+ return cvm::error("Error: The number of positions read from file \""+
std::string(filename)+"\" does not match the number of "+ std::string(filename)+"\" does not match the number of "+
"positions required: "+cvm::to_str(xyz_natoms)+" vs. "+ "positions required: "+cvm::to_str(xyz_natoms)+" vs. "+

View File

@ -10,7 +10,7 @@
#ifndef COLVARMODULE_H #ifndef COLVARMODULE_H
#define COLVARMODULE_H #define COLVARMODULE_H
#include <cmath> #include <cstdint>
#include "colvars_version.h" #include "colvars_version.h"
@ -19,9 +19,11 @@
#endif #endif
/*! \mainpage Main page /*! \mainpage Main page
This is the Developer's documentation for the Collective Variables Module. This is the Developer's documentation for the Collective Variables module (Colvars).
You can browse the class hierarchy or the list of source files. You can browse the class hierarchy or the list of source files.
Please note that this documentation is only supported for the master branch, and its features may differ from those in a given release of a simulation package.
*/ */
/// \file colvarmodule.h /// \file colvarmodule.h
@ -33,26 +35,15 @@ You can browse the class hierarchy or the list of source files.
/// shared between all object instances) to be accessed from other /// shared between all object instances) to be accessed from other
/// objects. /// objects.
#define COLVARS_OK 0 #include <cmath>
#define COLVARS_ERROR 1 #include <iosfwd>
#define COLVARS_NOT_IMPLEMENTED (1<<1)
#define COLVARS_INPUT_ERROR (1<<2) // out of bounds or inconsistent input
#define COLVARS_BUG_ERROR (1<<3) // Inconsistent state indicating bug
#define COLVARS_FILE_ERROR (1<<4)
#define COLVARS_MEMORY_ERROR (1<<5)
#define COLVARS_NO_SUCH_FRAME (1<<6) // Cannot load the requested frame
#include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <list>
#include <iosfwd>
class colvarparse; class colvarparse;
class colvar; class colvar;
class colvarbias; class colvarbias;
class colvarproxy; class colvarproxy;
class colvarscript;
class colvarvalue; class colvarvalue;
@ -67,14 +58,6 @@ class colvarvalue;
/// child objects /// child objects
class colvarmodule { class colvarmodule {
private:
/// Impossible to initialize the main object without arguments
colvarmodule();
/// Integer representing the version string (allows comparisons)
int version_int;
public: public:
/// Get the version string (YYYY-MM-DD format) /// Get the version string (YYYY-MM-DD format)
@ -89,9 +72,21 @@ public:
return version_int; return version_int;
} }
friend class colvarproxy; /// Get the patch version number (non-zero in patch releases of other packages)
// TODO colvarscript should be unaware of colvarmodule's internals int patch_version_number() const
friend class colvarscript; {
return patch_version_int;
}
private:
/// Integer representing the version string (allows comparisons)
int version_int = 0;
/// Patch version number (non-zero in patch releases of other packages)
int patch_version_int = 0;
public:
/// Use a 64-bit integer to store the step number /// Use a 64-bit integer to store the step number
typedef long long step_number; typedef long long step_number;
@ -190,7 +185,9 @@ public:
template <class T> class matrix2d; template <class T> class matrix2d;
class quaternion; class quaternion;
class rotation; class rotation;
class usage; class usage;
class memory_stream;
/// Residue identifier /// Residue identifier
typedef int residue_id; typedef int residue_id;
@ -205,8 +202,6 @@ public:
// allow these classes to access protected data // allow these classes to access protected data
class atom; class atom;
class atom_group; class atom_group;
friend class atom;
friend class atom_group;
typedef std::vector<atom>::iterator atom_iter; typedef std::vector<atom>::iterator atom_iter;
typedef std::vector<atom>::const_iterator atom_const_iter; typedef std::vector<atom>::const_iterator atom_const_iter;
@ -247,6 +242,8 @@ public:
return it; return it;
} }
bool binary_restart;
/// \brief Finite difference step size (if there is no dynamics, or /// \brief Finite difference step size (if there is no dynamics, or
/// if gradients need to be tested independently from the size of /// if gradients need to be tested independently from the size of
/// dt) /// dt)
@ -342,9 +339,19 @@ public:
/// \param Pointer to instance of the proxy class (communicate with engine) /// \param Pointer to instance of the proxy class (communicate with engine)
colvarmodule(colvarproxy *proxy); colvarmodule(colvarproxy *proxy);
private:
/// Cannot initialize the main object without a proxy
colvarmodule();
public:
/// Destructor /// Destructor
~colvarmodule(); ~colvarmodule();
/// Set the initial step number (it is 0 otherwise); may be overridden when reading a state
void set_initial_step(step_number it);
/// Actual function called by the destructor /// Actual function called by the destructor
int reset(); int reset();
@ -449,17 +456,52 @@ public:
/// (Re)initialize the output trajectory and state file (does not write it yet) /// (Re)initialize the output trajectory and state file (does not write it yet)
int setup_output(); int setup_output();
/// Read a restart file private:
std::istream & read_restart(std::istream &is);
template <typename IST> IST & read_state_template_(IST &is);
/// Default input state file; if given, it is read unless the MD engine provides it
std::string default_input_state_file_;
/// Internal state buffer, to be read as an unformatted stream
std::vector<unsigned char> input_state_buffer_;
public:
/// Read all objects' state fron a formatted (text) stream
std::istream & read_state(std::istream &is);
/// Read all objects' state fron an unformatted (binary) stream
memory_stream & read_state(memory_stream &is);
/// Set an internal state buffer, to be read later as an unformatted stream when ready
int set_input_state_buffer(size_t n, unsigned char *buf);
/// Same as set_input_state_buffer() for C array, but uses std::move
int set_input_state_buffer(std::vector<unsigned char> &buf);
/// Read the states of individual objects; allows for changes /// Read the states of individual objects; allows for changes
std::istream & read_objects_state(std::istream &is); std::istream & read_objects_state(std::istream &is);
/// Read the states of individual objects; allows for changes
memory_stream & read_objects_state(memory_stream &is);
/// If needed (old restart file), print the warning that cannot be ignored /// If needed (old restart file), print the warning that cannot be ignored
int print_total_forces_errning(bool warn_total_forces); int print_total_forces_errning(bool warn_total_forces);
/// Write the output restart file private:
std::ostream & write_restart(std::ostream &os); template <typename OST> OST &write_state_template_(OST &os);
public:
/// Write the state of the module to a formatted (text) file
std::ostream & write_state(std::ostream &os);
/// Write the state of the module to an unformatted (binary) file
memory_stream & write_state(memory_stream &os);
/// Write the state of the module to an array of bytes (wrapped as a memory_stream object)
int write_state_buffer(std::vector<unsigned char> &buffer);
/// Strips .colvars.state from filename and checks that it is not empty /// Strips .colvars.state from filename and checks that it is not empty
static std::string state_file_prefix(char const *filename); static std::string state_file_prefix(char const *filename);
@ -650,7 +692,7 @@ public:
static void log(std::string const &message, int min_log_level = 10); static void log(std::string const &message, int min_log_level = 10);
/// Print a message to the main log and set global error code /// Print a message to the main log and set global error code
static int error(std::string const &message, int code = COLVARS_ERROR); static int error(std::string const &message, int code = -1);
private: private:
@ -715,17 +757,6 @@ public:
/// Clear the index groups loaded so far /// Clear the index groups loaded so far
int reset_index_groups(); int reset_index_groups();
/// \brief Select atom IDs from a file (usually PDB) \param filename name of
/// the file \param atoms array into which atoms read from "filename" will be
/// appended \param pdb_field (optional) if the file is a PDB and this
/// string is non-empty, select atoms for which this field is non-zero
/// \param pdb_field_value (optional) if non-zero, select only atoms whose
/// pdb_field equals this
static int load_atoms(char const *filename,
atom_group &atoms,
std::string const &pdb_field,
double pdb_field_value = 0.0);
/// \brief Load coordinates for a group of atoms from a file (PDB or XYZ); /// \brief Load coordinates for a group of atoms from a file (PDB or XYZ);
/// if "pos" is already allocated, the number of its elements must match the /// if "pos" is already allocated, the number of its elements must match the
/// number of entries in "filename" \param filename name of the file \param /// number of entries in "filename" \param filename name of the file \param
@ -755,7 +786,7 @@ public:
std::string restart_out_name; std::string restart_out_name;
/// Pseudo-random number with Gaussian distribution /// Pseudo-random number with Gaussian distribution
static real rand_gaussian(void); static real rand_gaussian();
protected: protected:
@ -838,9 +869,20 @@ public:
typedef colvarmodule cvm; typedef colvarmodule cvm;
std::ostream & operator << (std::ostream &os, cvm::rvector const &v); std::ostream & operator << (std::ostream &os, cvm::rvector const &v);
std::istream & operator >> (std::istream &is, cvm::rvector &v); std::istream & operator >> (std::istream &is, cvm::rvector &v);
namespace {
constexpr int32_t COLVARS_OK = 0;
constexpr int32_t COLVARS_ERROR = 1;
constexpr int32_t COLVARS_NOT_IMPLEMENTED = (1<<1);
constexpr int32_t COLVARS_INPUT_ERROR = (1<<2); // out of bounds or inconsistent input
constexpr int32_t COLVARS_BUG_ERROR = (1<<3); // Inconsistent state indicating bug
constexpr int32_t COLVARS_FILE_ERROR = (1<<4);
constexpr int32_t COLVARS_MEMORY_ERROR = (1<<5);
constexpr int32_t COLVARS_NO_SUCH_FRAME = (1<<6); // Cannot load the requested frame
}
#endif #endif

View File

@ -14,6 +14,22 @@
" url = {https://doi.org/10.1016/j.softx.2015.06.001}\n" " url = {https://doi.org/10.1016/j.softx.2015.06.001}\n"
"}\n"; "}\n";
paper_count_[std::string("BouRabee2010")] = 0;
paper_url_[std::string("BouRabee2010")] = "https://doi.org/10.1137/090758842";
paper_bibtex_[std::string("BouRabee2010")] =
"\n"
"@article{BouRabee2010,\n"
" doi = {10.1137/090758842},\n"
" url = {https://doi.org/10.1137/090758842},\n"
" year = {2010},\n"
" volume = {48},\n"
" number = {1},\n"
" pages = {278--297},\n"
" author = {Nawaf Bou-Rabee and Houman Owhadi},\n"
" title = {Long-Run Accuracy of Variational Integrators in the Stochastic Context},\n"
" journal = {{SIAM} Journal on Numerical Analysis}\n"
"}\n";
paper_count_[std::string("Chen2021")] = 0; paper_count_[std::string("Chen2021")] = 0;
paper_url_[std::string("Chen2021")] = "https://doi.org/10.1021/acs.jctc.1c00103"; paper_url_[std::string("Chen2021")] = "https://doi.org/10.1021/acs.jctc.1c00103";
paper_bibtex_[std::string("Chen2021")] = paper_bibtex_[std::string("Chen2021")] =
@ -182,6 +198,19 @@
" url = {https://doi.org/10.1021/ct9004432}\n" " url = {https://doi.org/10.1021/ct9004432}\n"
"}\n"; "}\n";
paper_count_[std::string("Henin2021")] = 0;
paper_url_[std::string("Henin2021")] = "https://doi.org/10.1021/acs.jctc.1c00593";
paper_bibtex_[std::string("Henin2021")] =
"\n"
"@Article{Henin2021,\n"
" author = {H\\'enin, J.},\n"
" journal = {J. Chem. Theory Comput.},\n"
" title = {Fast and accurate multidimensional free energy integration},\n"
" year = {2021},\n"
" doi = {10.1021/acs.jctc.1c00593},\n"
" url = {https://doi.org/10.1021/acs.jctc.1c00593},\n"
"}\n";
paper_count_[std::string("Humphrey1996")] = 0; paper_count_[std::string("Humphrey1996")] = 0;
paper_url_[std::string("Humphrey1996")] = "https://doi.org/10.1016/0263-7855(96)00018-5"; paper_url_[std::string("Humphrey1996")] = "https://doi.org/10.1016/0263-7855(96)00018-5";
paper_bibtex_[std::string("Humphrey1996")] = paper_bibtex_[std::string("Humphrey1996")] =
@ -215,19 +244,6 @@
" url = {https://doi.org/10.1021/acs.jpcb.6b10055}\n" " url = {https://doi.org/10.1021/acs.jpcb.6b10055}\n"
"}\n"; "}\n";
paper_count_[std::string("Henin2021")] = 0;
paper_url_[std::string("Henin2021")] = "https://doi.org/10.1021/acs.jctc.1c00593";
paper_bibtex_[std::string("Henin2021")] =
"\n"
"@Article{Henin2021,\n"
" author = {H\\'enin, J.},\n"
" journal = {J. Chem. Theory Comput.},\n"
" title = {Fast and accurate multidimensional free energy integration},\n"
" year = {2021},\n"
" doi = {10.1021/acs.jctc.1c00593},\n"
" url = {https://doi.org/10.1021/acs.jctc.1c00593},\n"
"}\n";
paper_count_[std::string("Marinelli2015")] = 0; paper_count_[std::string("Marinelli2015")] = 0;
paper_url_[std::string("Marinelli2015")] = "https://doi.org/10.1016/j.bpj.2015.05.024"; paper_url_[std::string("Marinelli2015")] = "https://doi.org/10.1016/j.bpj.2015.05.024";
paper_bibtex_[std::string("Marinelli2015")] = paper_bibtex_[std::string("Marinelli2015")] =
@ -335,6 +351,9 @@
feature_count_[std::string("GROMACS engine")] = 0; feature_count_[std::string("GROMACS engine")] = 0;
feature_paper_map_[std::string("GROMACS engine")] = "Abraham2015"; feature_paper_map_[std::string("GROMACS engine")] = "Abraham2015";
feature_count_[std::string("BAOA integrator")] = 0;
feature_paper_map_[std::string("BAOA integrator")] = "BouRabee2010";
feature_count_[std::string("reweightaMD colvar bias implementation (NAMD)")] = 0; feature_count_[std::string("reweightaMD colvar bias implementation (NAMD)")] = 0;
feature_paper_map_[std::string("reweightaMD colvar bias implementation (NAMD)")] = "Chen2021"; feature_paper_map_[std::string("reweightaMD colvar bias implementation (NAMD)")] = "Chen2021";
@ -422,14 +441,14 @@
feature_count_[std::string("orientationAngle colvar component (derived from orientation)")] = 0; feature_count_[std::string("orientationAngle colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("orientationAngle colvar component (derived from orientation)")] = "Fiorin2013"; feature_paper_map_[std::string("orientationAngle colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("orientationProj colvar component (derived from orientation)")] = 0; feature_count_[std::string("orientationProj colvar component (derived from orientationAngle)")] = 0;
feature_paper_map_[std::string("orientationProj colvar component (derived from orientation)")] = "Fiorin2013"; feature_paper_map_[std::string("orientationProj colvar component (derived from orientationAngle)")] = "Fiorin2013";
feature_count_[std::string("spinAngle colvar component (derived from orientation)")] = 0; feature_count_[std::string("spinAngle colvar component (derived from tilt)")] = 0;
feature_paper_map_[std::string("spinAngle colvar component (derived from orientation)")] = "Fiorin2013"; feature_paper_map_[std::string("spinAngle colvar component (derived from tilt)")] = "Fiorin2013";
feature_count_[std::string("tilt colvar component (derived from orientation)")] = 0; feature_count_[std::string("tilt colvar component (derived from orientationProj)")] = 0;
feature_paper_map_[std::string("tilt colvar component (derived from orientation)")] = "Fiorin2013"; feature_paper_map_[std::string("tilt colvar component (derived from orientationProj)")] = "Fiorin2013";
feature_count_[std::string("alpha colvar component")] = 0; feature_count_[std::string("alpha colvar component")] = 0;
feature_paper_map_[std::string("alpha colvar component")] = "Fiorin2013"; feature_paper_map_[std::string("alpha colvar component")] = "Fiorin2013";
@ -479,14 +498,14 @@
feature_count_[std::string("polarPhi colvar component")] = 0; feature_count_[std::string("polarPhi colvar component")] = 0;
feature_paper_map_[std::string("polarPhi colvar component")] = "Fu2017"; feature_paper_map_[std::string("polarPhi colvar component")] = "Fu2017";
feature_count_[std::string("eulerPhi colvar component (derived from orientation)")] = 0; feature_count_[std::string("eulerPhi colvar component (derived from orientation_angle)")] = 0;
feature_paper_map_[std::string("eulerPhi colvar component (derived from orientation)")] = "Fu2017"; feature_paper_map_[std::string("eulerPhi colvar component (derived from orientation_angle)")] = "Fu2017";
feature_count_[std::string("eulerTheta colvar component (derived from orientation)")] = 0; feature_count_[std::string("eulerTheta colvar component (derived from orientation_angle)")] = 0;
feature_paper_map_[std::string("eulerTheta colvar component (derived from orientation)")] = "Fu2017"; feature_paper_map_[std::string("eulerTheta colvar component (derived from orientation_angle)")] = "Fu2017";
feature_count_[std::string("eulerPsi colvar component (derived from orientation)")] = 0; feature_count_[std::string("eulerPsi colvar component (derived from orientation_angle)")] = 0;
feature_paper_map_[std::string("eulerPsi colvar component (derived from orientation)")] = "Fu2017"; feature_paper_map_[std::string("eulerPsi colvar component (derived from orientation_angle)")] = "Fu2017";
feature_count_[std::string("dipoleAngle colvar component")] = 0; feature_count_[std::string("dipoleAngle colvar component")] = 0;
feature_paper_map_[std::string("dipoleAngle colvar component")] = "Garate2019"; feature_paper_map_[std::string("dipoleAngle colvar component")] = "Garate2019";
@ -500,6 +519,9 @@
feature_count_[std::string("Internal-forces free energy estimator")] = 0; feature_count_[std::string("Internal-forces free energy estimator")] = 0;
feature_paper_map_[std::string("Internal-forces free energy estimator")] = "Henin2010"; feature_paper_map_[std::string("Internal-forces free energy estimator")] = "Henin2010";
feature_count_[std::string("Poisson integration of 2D/3D free energy surfaces")] = 0;
feature_paper_map_[std::string("Poisson integration of 2D/3D free energy surfaces")] = "Henin2021";
feature_count_[std::string("VMD engine")] = 0; feature_count_[std::string("VMD engine")] = 0;
feature_paper_map_[std::string("VMD engine")] = "Humphrey1996"; feature_paper_map_[std::string("VMD engine")] = "Humphrey1996";
@ -509,9 +531,6 @@
feature_count_[std::string("CZAR eABF estimator")] = 0; feature_count_[std::string("CZAR eABF estimator")] = 0;
feature_paper_map_[std::string("CZAR eABF estimator")] = "Lesage2017"; feature_paper_map_[std::string("CZAR eABF estimator")] = "Lesage2017";
feature_count_[std::string("Poisson integration of 2D/3D free energy surfaces")] = 0;
feature_paper_map_[std::string("Poisson integration of 2D/3D free energy surfaces")] = "Henin2021";
feature_count_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = 0; feature_count_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = 0;
feature_paper_map_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = "Marinelli2015"; feature_paper_map_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = "Marinelli2015";
@ -539,9 +558,6 @@
feature_count_[std::string("Colvars-GROMACS interface")] = 0; feature_count_[std::string("Colvars-GROMACS interface")] = 0;
feature_paper_map_[std::string("Colvars-GROMACS interface")] = "n/a"; feature_paper_map_[std::string("Colvars-GROMACS interface")] = "n/a";
feature_count_[std::string("Colvars Dashboard (Colvars-VMD graphical user interface)")] = 0;
feature_paper_map_[std::string("Colvars Dashboard (Colvars-VMD graphical user interface)")] = "n/a";
feature_count_[std::string("gspath colvar component")] = 0; feature_count_[std::string("gspath colvar component")] = 0;
feature_paper_map_[std::string("gspath colvar component")] = "n/a"; feature_paper_map_[std::string("gspath colvar component")] = "n/a";
@ -571,3 +587,6 @@
feature_count_[std::string("Scripted functions (Tcl)")] = 0; feature_count_[std::string("Scripted functions (Tcl)")] = 0;
feature_paper_map_[std::string("Scripted functions (Tcl)")] = "n/a"; feature_paper_map_[std::string("Scripted functions (Tcl)")] = "n/a";
feature_count_[std::string("ABMD bias")] = 0;
feature_paper_map_[std::string("ABMD bias")] = "n/a";

View File

@ -8,12 +8,12 @@
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <sstream> #include <sstream>
#include <iostream>
#include <algorithm> #include <algorithm>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarparse.h" #include "colvarparse.h"
#include "colvars_memstream.h"
// space & tab // space & tab
@ -100,7 +100,7 @@ bool colvarparse::get_key_string_multi_value(std::string const &conf,
char const *key, std::vector<std::string>& data) char const *key, std::vector<std::string>& data)
{ {
bool b_found = false, b_found_any = false; bool b_found = false, b_found_any = false;
size_t save_pos = 0, found_count = 0; size_t save_pos = 0;
data.clear(); data.clear();
@ -110,7 +110,6 @@ bool colvarparse::get_key_string_multi_value(std::string const &conf,
if (b_found) { if (b_found) {
if (!b_found_any) if (!b_found_any)
b_found_any = true; b_found_any = true;
found_count++;
data.push_back(data_this); data.push_back(data_this);
} }
} while (b_found); } while (b_found);
@ -786,14 +785,12 @@ bool colvarparse::key_lookup(std::string const &conf,
if (line[brace] == '{') brace_count++; if (line[brace] == '{') brace_count++;
if (line[brace] == '}') brace_count--; if (line[brace] == '}') brace_count--;
if (brace_count == 0) { if (brace_count == 0) {
data_end = brace+1;
break; break;
} }
brace = line.find_first_of("{}", brace+1); brace = line.find_first_of("{}", brace+1);
} }
if (brace_count == 0) { if (brace_count == 0) {
data_end = brace+1;
break; break;
} }
@ -869,55 +866,107 @@ colvarparse::read_block::~read_block()
std::istream & operator>> (std::istream &is, colvarparse::read_block const &rb) std::istream & operator>> (std::istream &is, colvarparse::read_block const &rb)
{ {
std::streampos start_pos = is.tellg(); auto start_pos = is.tellg();
std::string read_key, next;
if ( !(is >> read_key) || !(read_key == rb.key) || std::string read_key;
!(is >> next) ) { if ( !(is >> read_key) || !(read_key == rb.key) ) {
// the requested keyword has not been found, or it is not possible // the requested keyword has not been found
// to read data after it
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
return is; return is;
} }
if (next != "{") { std::string next;
if (rb.data) { if (is >> next) {
*(rb.data) = next; if (next == "{") {
// Parse a formatted brace-delimited block
rb.read_block_contents(is);
} else {
if (rb.data) {
*(rb.data) = next;
}
} }
return is; } else {
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::badbit);
} }
size_t brace_count = 1; return is;
}
std::istream &colvarparse::read_block::read_block_contents(std::istream &is,
bool block_only) const
{
int brace_count = block_only ? 0 : 1;
auto const start_pos = is.tellg();
std::string line; std::string line;
while (colvarparse::getline_nocomments(is, line)) { while (colvarparse::getline_nocomments(is, line)) {
size_t br = 0, br_old = 0; size_t br = 0, br_old = 0;
while ( (br = line.find_first_of("{}", br)) != std::string::npos) { while ((br = line.find_first_of("{}", br)) != std::string::npos) {
if (line[br] == '{') brace_count++; if (line[br] == '{')
if (line[br] == '}') brace_count--; brace_count++;
if (line[br] == '}')
brace_count--;
br_old = br; br_old = br;
br++; br++;
} }
if (brace_count) { if (brace_count || block_only) {
if (rb.data) { // Add whole line if (1) brace are unmatched or (2) we're reading the whole stream anyway
(rb.data)->append(line + "\n"); if (data) {
data->append(line + "\n");
} }
} } else {
else { // Not reading whole block and braces are matched; add until before the last brace
if (rb.data) { if (data) {
(rb.data)->append(line, 0, br_old); data->append(line.substr(0, br_old) + "\n");
} }
break; break;
} }
} }
if (brace_count) {
// end-of-file reached if (block_only) {
// restore initial position if (is.rdstate() & std::ios::eofbit) {
is.clear(); // Clear EOF errors if we were meant to read the whole block
is.seekg(start_pos, std::ios::beg); is.clear();
is.setstate(std::ios::failbit); }
} else {
if (brace_count) {
// Could not match braces, restore initial position and set fail bit
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
}
} }
return is;
}
cvm::memory_stream &operator>>(cvm::memory_stream &is, colvarparse::read_block const &rb)
{
auto const start_pos = is.tellg();
std::string read_key;
if ( !(is >> read_key) || !(read_key == rb.key) ) {
// the requested keyword has not been found
is.clear();
is.seekg(start_pos);
is.setstate(std::ios::failbit);
return is;
}
std::string content;
if (is >> content) {
std::istringstream iss(content);
if (!rb.read_block_contents(iss, true)) {
is.seekg(start_pos);
is.setstate(std::ios::failbit);
}
}
return is; return is;
} }

View File

@ -11,6 +11,7 @@
#define COLVARPARSE_H #define COLVARPARSE_H
#include <cstring> #include <cstring>
#include <list>
#include <string> #include <string>
#include "colvarmodule.h" #include "colvarmodule.h"
@ -40,7 +41,7 @@ public:
void set_string(std::string const &conf); void set_string(std::string const &conf);
/// Default destructor /// Default destructor
virtual ~colvarparse(); ~colvarparse() override;
/// Get the configuration string (includes comments) /// Get the configuration string (includes comments)
inline std::string const & get_config() const inline std::string const & get_config() const
@ -109,12 +110,12 @@ public:
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
int &value, int &value,
int const &def_value = (int)0, int const &def_value = 0,
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
size_t &value, size_t &value,
size_t const &def_value = (size_t)0, size_t const &def_value = 0,
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
@ -134,7 +135,7 @@ public:
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
cvm::real &value, cvm::real &value,
cvm::real const &def_value = (cvm::real)0.0, cvm::real const &def_value = 0.0,
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
@ -159,17 +160,17 @@ public:
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
std::vector<int> &values, std::vector<int> &values,
std::vector<int> const &def_values = std::vector<int>(0, (int)0), std::vector<int> const &def_values = std::vector<int>(0, 0),
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
std::vector<size_t> &values, std::vector<size_t> &values,
std::vector<size_t> const &def_values = std::vector<size_t>(0, (size_t)0), std::vector<size_t> const &def_values = std::vector<size_t>(0, 0),
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
std::vector<long> &values, std::vector<long> &values,
std::vector<long> const &def_values = std::vector<long>(0, (long)0), std::vector<long> const &def_values = std::vector<long>(0, 0),
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
@ -179,7 +180,7 @@ public:
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
std::vector<cvm::real> &values, std::vector<cvm::real> &values,
std::vector<cvm::real> const &def_values = std::vector<cvm::real>(0, (cvm::real)0.0), std::vector<cvm::real> const &def_values = std::vector<cvm::real>(0, 0.0),
Parse_Mode const parse_mode = parse_normal); Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf, bool get_keyval(std::string const &conf,
char const *key, char const *key,
@ -262,33 +263,41 @@ public:
{ {
std::string out = ""; std::string out = "";
for (size_t i = 0; i < in.size(); i++) { for (size_t i = 0; i < in.size(); i++) {
out.append(1, (char) ::tolower(in[i]) ); out.append(1, static_cast<char>( ::tolower(in[i])) );
} }
return out; return out;
} }
/// \brief Helper class to read a block of the type "key { ... }" /// Helper class to read a block "key { ... }" from a stream and store it in a string
/// from a stream and store it in a string
/// ///
/// Useful on restarts, where the file is too big to be loaded in a /// Useful on restarts, where the file is too big to be loaded in a string
/// string by key_lookup; it can only check that the keyword is /// by key_lookup(); it can only check that the keyword is correct and the
/// correct and the block is properly delimited by braces, not /// block is properly delimited by braces, not skipping other blocks
/// skipping other blocks
class read_block { class read_block {
/// The keyword that identifies the block
std::string const key;
/// Where to keep the data (may be NULL)
std::string * const data;
public: public:
read_block(std::string const &key_in, std::string *data_in = NULL); read_block(std::string const &key, std::string *data = nullptr);
~read_block(); ~read_block();
/// Read block from stream, first check that key matches, then call read_contents()
friend std::istream & operator >> (std::istream &is, read_block const &rb); friend std::istream & operator >> (std::istream &is, read_block const &rb);
/// Read block from stream, first check that key matches, then call read_contents()
friend cvm::memory_stream & operator >> (cvm::memory_stream &is, read_block const &rb);
private:
/// Keyword that identifies the block
std::string const key;
/// Where to keep the data
std::string * const data;
/// Read the contents of a formatted block after checking that the keyword matches
/// \param[in] is Stream object
/// \param[in] block_only If true, stream is assumed to contain only the block without braces
std::istream & read_block_contents(std::istream &is, bool block_only = false) const;
}; };
@ -304,8 +313,8 @@ public:
/// within "conf", useful when doing multiple calls /// within "conf", useful when doing multiple calls
bool key_lookup(std::string const &conf, bool key_lookup(std::string const &conf,
char const *key, char const *key,
std::string *data = NULL, std::string *data = nullptr,
size_t *save_pos = NULL); size_t *save_pos = nullptr);
/// \brief Reads a configuration line, adds it to config_string, and returns /// \brief Reads a configuration line, adds it to config_string, and returns
/// the stream \param is Input stream \param line String that will hold the /// the stream \param is Input stream \param line String that will hold the

View File

@ -13,8 +13,9 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvar.h"
#include "colvarbias.h"
#include "colvarscript.h" #include "colvarscript.h"
#include "colvaratoms.h"
#include "colvarmodule_utils.h" #include "colvarmodule_utils.h"
@ -23,6 +24,7 @@ colvarproxy_atoms::colvarproxy_atoms()
{ {
atoms_rms_applied_force_ = atoms_max_applied_force_ = 0.0; atoms_rms_applied_force_ = atoms_max_applied_force_ = 0.0;
atoms_max_applied_force_id_ = -1; atoms_max_applied_force_id_ = -1;
modified_atom_list_ = false;
updated_masses_ = updated_charges_ = false; updated_masses_ = updated_charges_ = false;
} }
@ -55,6 +57,7 @@ int colvarproxy_atoms::add_atom_slot(int atom_id)
atoms_positions.push_back(cvm::rvector(0.0, 0.0, 0.0)); atoms_positions.push_back(cvm::rvector(0.0, 0.0, 0.0));
atoms_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); atoms_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
atoms_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); atoms_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
modified_atom_list_ = true;
return (atoms_ids.size() - 1); return (atoms_ids.size() - 1);
} }
@ -71,6 +74,12 @@ int colvarproxy_atoms::check_atom_id(int /* atom_number */)
} }
int colvarproxy_atoms::check_atom_name_selections_available()
{
return COLVARS_NOT_IMPLEMENTED;
}
int colvarproxy_atoms::init_atom(cvm::residue_id const & /* residue */, int colvarproxy_atoms::init_atom(cvm::residue_id const & /* residue */,
std::string const & /* atom_name */, std::string const & /* atom_name */,
std::string const & /* segment_id */) std::string const & /* segment_id */)
@ -112,29 +121,6 @@ size_t colvarproxy_atoms::get_num_active_atoms() const
} }
int colvarproxy_atoms::load_atoms(char const * /* filename */,
cvm::atom_group & /* atoms */,
std::string const & /* pdb_field */,
double)
{
return cvm::error("Error: loading atom identifiers from a file "
"is currently not implemented.\n",
COLVARS_NOT_IMPLEMENTED);
}
int colvarproxy_atoms::load_coords(char const * /* filename */,
std::vector<cvm::atom_pos> & /* pos */,
std::vector<int> const & /* sorted_ids */,
std::string const & /* pdb_field */,
double)
{
return cvm::error("Error: loading atomic coordinates from a file "
"is currently not implemented.\n",
COLVARS_NOT_IMPLEMENTED);
}
void colvarproxy_atoms::compute_rms_atoms_applied_force() void colvarproxy_atoms::compute_rms_atoms_applied_force()
{ {
atoms_rms_applied_force_ = atoms_rms_applied_force_ =
@ -280,7 +266,7 @@ colvarproxy_smp::~colvarproxy_smp()
} }
int colvarproxy_smp::smp_enabled() int colvarproxy_smp::check_smp_enabled()
{ {
#if defined(_OPENMP) #if defined(_OPENMP)
if (b_smp_active) { if (b_smp_active) {
@ -299,7 +285,7 @@ int colvarproxy_smp::smp_colvars_loop()
colvarmodule *cv = cvm::main(); colvarmodule *cv = cvm::main();
colvarproxy *proxy = cv->proxy; colvarproxy *proxy = cv->proxy;
#pragma omp parallel for #pragma omp parallel for
for (size_t i = 0; i < cv->variables_active_smp()->size(); i++) { for (int i = 0; i < static_cast<int>(cv->variables_active_smp()->size()); i++) {
colvar *x = (*(cv->variables_active_smp()))[i]; colvar *x = (*(cv->variables_active_smp()))[i];
int x_item = (*(cv->variables_active_smp_items()))[i]; int x_item = (*(cv->variables_active_smp_items()))[i];
if (cvm::debug()) { if (cvm::debug()) {
@ -324,7 +310,7 @@ int colvarproxy_smp::smp_biases_loop()
#pragma omp parallel #pragma omp parallel
{ {
#pragma omp for #pragma omp for
for (size_t i = 0; i < cv->biases_active()->size(); i++) { for (int i = 0; i < static_cast<int>(cv->biases_active()->size()); i++) {
colvarbias *b = (*(cv->biases_active()))[i]; colvarbias *b = (*(cv->biases_active()))[i];
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Calculating bias \""+b->name+"\" on thread "+ cvm::log("Calculating bias \""+b->name+"\" on thread "+
@ -351,7 +337,7 @@ int colvarproxy_smp::smp_biases_script_loop()
cv->calc_scripted_forces(); cv->calc_scripted_forces();
} }
#pragma omp for #pragma omp for
for (size_t i = 0; i < cv->biases_active()->size(); i++) { for (int i = 0; i < static_cast<int>(cv->biases_active()->size()); i++) {
colvarbias *b = (*(cv->biases_active()))[i]; colvarbias *b = (*(cv->biases_active()))[i];
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Calculating bias \""+b->name+"\" on thread "+ cvm::log("Calculating bias \""+b->name+"\" on thread "+
@ -484,16 +470,21 @@ colvarproxy::~colvarproxy()
bool colvarproxy::io_available() bool colvarproxy::io_available()
{ {
return (smp_enabled() == COLVARS_OK && smp_thread_id() == 0) || return (check_smp_enabled() == COLVARS_OK && smp_thread_id() == 0) ||
(smp_enabled() != COLVARS_OK); (check_smp_enabled() != COLVARS_OK);
} }
int colvarproxy::reset() int colvarproxy::reset()
{ {
if (cvm::debug()) {
cvm::log("colvarproxy::reset()\n");
}
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
error_code |= colvarproxy_atoms::reset(); error_code |= colvarproxy_atoms::reset();
error_code |= colvarproxy_atom_groups::reset(); error_code |= colvarproxy_atom_groups::reset();
error_code |= colvarproxy_volmaps::reset();
total_force_requested = false;
return error_code; return error_code;
} }
@ -541,6 +532,31 @@ int colvarproxy::parse_module_config()
} }
int colvarproxy::load_atoms_pdb(char const * /* filename */,
cvm::atom_group & /* atoms */,
std::string const & /* pdb_field */,
double /* pdb_field_value */)
{
return cvm::error(
"Error: loading atom indices from a PDB file is currently not implemented in " +
engine_name() + ".\n",
COLVARS_NOT_IMPLEMENTED);
}
int colvarproxy::load_coords_pdb(char const * /* filename */,
std::vector<cvm::atom_pos> & /* pos */,
std::vector<int> const & /* sorted_ids */,
std::string const & /* pdb_field */,
double /* pdb_field_value */)
{
return cvm::error(
"Error: loading atomic coordinates from a PDB file is currently not implemented in " +
engine_name() + ".\n",
COLVARS_NOT_IMPLEMENTED);
}
int colvarproxy::update_input() int colvarproxy::update_input()
{ {
return COLVARS_OK; return COLVARS_OK;
@ -591,47 +607,78 @@ void colvarproxy::print_input_atomic_data()
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_ids = "+cvm::to_str(atoms_ids)+"\n"); "atoms_ids[size = "+cvm::to_str(atoms_ids.size())+
"] = "+cvm::to_str(atoms_ids)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_refcount = "+cvm::to_str(atoms_refcount)+"\n"); "atoms_refcount[size = "+cvm::to_str(atoms_refcount.size())+
"] = "+cvm::to_str(atoms_refcount)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_masses = "+cvm::to_str(atoms_masses)+"\n"); "atoms_masses[size = "+cvm::to_str(atoms_masses.size())+
"] = "+cvm::to_str(atoms_masses)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_charges = "+cvm::to_str(atoms_charges)+"\n"); "atoms_charges[size = "+cvm::to_str(atoms_charges.size())+
"] = "+cvm::to_str(atoms_charges)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_positions = "+cvm::to_str(atoms_positions, "atoms_positions[size = "+cvm::to_str(atoms_positions.size())+
cvm::cv_width, "] = "+cvm::to_str(atoms_positions,
cvm::cv_prec)+"\n"); cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_total_forces = "+cvm::to_str(atoms_total_forces, "atoms_total_forces[size = "+
cvm::cv_width, cvm::to_str(atoms_total_forces.size())+
cvm::cv_prec)+"\n"); "] = "+cvm::to_str(atoms_total_forces,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_ids = "+cvm::to_str(atom_groups_ids)+"\n"); "atom_groups_ids[size = "+cvm::to_str(atom_groups_ids.size())+
"] = "+cvm::to_str(atom_groups_ids)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_refcount = "+cvm::to_str(atom_groups_refcount)+"\n"); "atom_groups_refcount[size = "+
cvm::to_str(atom_groups_refcount.size())+
"] = "+cvm::to_str(atom_groups_refcount)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_masses = "+cvm::to_str(atom_groups_masses)+"\n"); "atom_groups_masses[size = "+
cvm::to_str(atom_groups_masses.size())+
"] = "+cvm::to_str(atom_groups_masses)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_charges = "+cvm::to_str(atom_groups_charges)+"\n"); "atom_groups_charges[size = "+
cvm::to_str(atom_groups_charges.size())+
"] = "+cvm::to_str(atom_groups_charges)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_coms = "+cvm::to_str(atom_groups_coms, "atom_groups_coms[size = "+
cvm::cv_width, cvm::to_str(atom_groups_coms.size())+
cvm::cv_prec)+"\n"); "] = "+cvm::to_str(atom_groups_coms,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_total_forces = "+cvm::to_str(atom_groups_total_forces, "atom_groups_total_forces[size = "+
cvm::cv_width, cvm::to_str(atom_groups_total_forces.size())+
cvm::cv_prec)+"\n"); "] = "+cvm::to_str(atom_groups_total_forces,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"volmaps_ids = "+cvm::to_str(volmaps_ids)+"\n"); "volmaps_ids[size = "+cvm::to_str(volmaps_ids.size())+
"] = "+cvm::to_str(volmaps_ids)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+ cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"volmaps_values = "+cvm::to_str(volmaps_values)+"\n"); "volmaps_values[size = "+cvm::to_str(volmaps_values.size())+
"] = "+cvm::to_str(volmaps_values)+"\n");
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
} }

View File

@ -12,7 +12,6 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvartypes.h" #include "colvartypes.h"
#include "colvarvalue.h"
#include "colvarproxy_io.h" #include "colvarproxy_io.h"
#include "colvarproxy_system.h" #include "colvarproxy_system.h"
#include "colvarproxy_tcl.h" #include "colvarproxy_tcl.h"
@ -56,6 +55,9 @@ public:
/// corresponding atom yet /// corresponding atom yet
virtual int check_atom_id(int atom_number); virtual int check_atom_id(int atom_number);
/// Check whether it is possible to select atoms by residue number name
virtual int check_atom_name_selections_available();
/// Select this atom for collective variables calculation, using name and /// Select this atom for collective variables calculation, using name and
/// residue number. Not all programs support this: leave this function as /// residue number. Not all programs support this: leave this function as
/// is in those cases. /// is in those cases.
@ -72,31 +74,6 @@ public:
/// (costly) set the corresponding atoms_refcount to zero /// (costly) set the corresponding atoms_refcount to zero
virtual void clear_atom(int index); virtual void clear_atom(int index);
/// \brief Select atom IDs from a file (usually PDB) \param filename name of
/// the file \param atoms array to which atoms read from "filename" will be
/// appended \param pdb_field (optional) if the file is a PDB and this
/// string is non-empty, select atoms for which this field is non-zero
/// \param pdb_field_value (optional) if non-zero, select only atoms whose
/// pdb_field equals this
virtual int load_atoms(char const *filename,
cvm::atom_group &atoms,
std::string const &pdb_field,
double pdb_field_value = 0.0);
/// \brief Load a set of coordinates from a file (usually PDB); if "pos" is
/// already allocated, the number of its elements must match the number of
/// entries in "filename" \param filename name of the file \param pos array
/// of coordinates \param sorted_ids array of sorted internal IDs, used to
/// loop through the file only once \param pdb_field (optional) if the file
/// is a PDB and this string is non-empty, select atoms for which this field
/// is non-zero \param pdb_field_value (optional) if non-zero, select only
/// atoms whose pdb_field equals this
virtual int load_coords(char const *filename,
std::vector<cvm::atom_pos> &pos,
std::vector<int> const &sorted_ids,
std::string const &pdb_field,
double pdb_field_value = 0.0);
/// Clear atomic data /// Clear atomic data
int reset(); int reset();
@ -245,6 +222,18 @@ public:
return atoms_max_applied_force_id_; return atoms_max_applied_force_id_;
} }
/// Whether the atom list has been modified internally
inline bool modified_atom_list() const
{
return modified_atom_list_;
}
/// Reset the modified atom list flag
inline void reset_modified_atom_list()
{
modified_atom_list_ = false;
}
/// Record whether masses have been updated /// Record whether masses have been updated
inline bool updated_masses() const inline bool updated_masses() const
{ {
@ -284,6 +273,9 @@ protected:
/// ID of the atom with the maximum norm among all applied forces /// ID of the atom with the maximum norm among all applied forces
int atoms_max_applied_force_id_; int atoms_max_applied_force_id_;
/// Whether the atom list has been modified internally
bool modified_atom_list_;
/// Whether the masses and charges have been updated from the host code /// Whether the masses and charges have been updated from the host code
bool updated_masses_, updated_charges_; bool updated_masses_, updated_charges_;
@ -466,7 +458,7 @@ public:
bool b_smp_active; bool b_smp_active;
/// Whether threaded parallelization is available (TODO: make this a cvm::deps feature) /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature)
virtual int smp_enabled(); virtual int check_smp_enabled();
/// Distribute calculation of colvars (and their components) across threads /// Distribute calculation of colvars (and their components) across threads
virtual int smp_colvars_loop(); virtual int smp_colvars_loop();
@ -565,9 +557,9 @@ public:
/// \brief Interface between the collective variables module and /// Interface between Colvars and MD engine (GROMACS, LAMMPS, NAMD, VMD...)
/// the simulation or analysis program (NAMD, VMD, LAMMPS...). ///
/// This is the base class: each interfaced program is supported by a derived class. /// This is the base class: each engine is supported by a derived class.
class colvarproxy class colvarproxy
: public colvarproxy_system, : public colvarproxy_system,
public colvarproxy_atoms, public colvarproxy_atoms,
@ -589,15 +581,20 @@ public:
colvarproxy(); colvarproxy();
/// Destructor /// Destructor
virtual ~colvarproxy(); ~colvarproxy() override;
virtual bool io_available() /* override */; inline std::string const &engine_name() const
{
return engine_name_;
}
bool io_available() override;
/// Request deallocation of the module (currently only implemented by VMD) /// Request deallocation of the module (currently only implemented by VMD)
virtual int request_deletion(); virtual int request_deletion();
/// Whether deallocation was requested /// Whether deallocation was requested
inline bool delete_requested() inline bool delete_requested() const
{ {
return b_delete_requested; return b_delete_requested;
} }
@ -608,6 +605,26 @@ public:
/// (Re)initialize the module /// (Re)initialize the module
virtual int parse_module_config(); virtual int parse_module_config();
/// \brief Read a selection of atom IDs from a PDB coordinate file
/// \param[in] filename name of the file
/// \param[in,out] atoms array into which atoms will be read from "filename"
/// \param[in] pdb_field if the file is a PDB and this string is non-empty,
/// select atoms for which this field is non-zero
/// \param[in] pdb_field_value if non-zero, select only atoms whose pdb_field equals this
virtual int load_atoms_pdb(char const *filename, cvm::atom_group &atoms,
std::string const &pdb_field, double pdb_field_value);
/// \brief Load a set of coordinates from a PDB file
/// \param[in] filename name of the file
/// \param[in,out] pos array of coordinates to fill; if not empty, the number of its elements must match
/// the number of entries in "filename"
/// \param[in] sorted_ids array of sorted internal IDs, used to loop through the file only once
/// \param[in] pdb_field if non-empty, only atoms for which this field is non-zero will be processed
/// \param[in] pdb_field_value if non-zero, process only atoms whose pdb_field equals this
virtual int load_coords_pdb(char const *filename, std::vector<cvm::atom_pos> &pos,
std::vector<int> const &sorted_ids, std::string const &pdb_field,
double pdb_field_value);
/// (Re)initialize required member data (called after the module) /// (Re)initialize required member data (called after the module)
virtual int setup(); virtual int setup();
@ -703,7 +720,10 @@ protected:
/// Track which features have been acknowledged during the last run /// Track which features have been acknowledged during the last run
size_t features_hash; size_t features_hash;
private: protected:
/// Name of the simulation engine that the derived proxy object supports
std::string engine_name_ = "standalone";
/// Queue of config strings or files to be fed to the module /// Queue of config strings or files to be fed to the module
void *config_queue_; void *config_queue_;

View File

@ -29,7 +29,6 @@
colvarproxy_io::colvarproxy_io() colvarproxy_io::colvarproxy_io()
{ {
input_buffer_ = NULL;
restart_frequency_engine = 0; restart_frequency_engine = 0;
input_stream_error_ = new std::istringstream(); input_stream_error_ = new std::istringstream();
input_stream_error_->setstate(std::ios::badbit); input_stream_error_->setstate(std::ios::badbit);
@ -135,7 +134,9 @@ int colvarproxy_io::rename_file(char const *filename, char const *newfilename)
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
// On straight Windows, must remove the destination before renaming it // On straight Windows, must remove the destination before renaming it
error_code |= remove_file(newfilename); if (_access(newfilename, 00) == 0) {
error_code |= remove_file(newfilename);
}
#endif #endif
int rename_exit_code = 0; int rename_exit_code = 0;
while ((rename_exit_code = std::rename(filename, newfilename)) != 0) { while ((rename_exit_code = std::rename(filename, newfilename)) != 0) {
@ -151,6 +152,51 @@ int colvarproxy_io::rename_file(char const *filename, char const *newfilename)
} }
int colvarproxy_io::set_input_prefix(std::string const &prefix)
{
// set input restart name and strip the extension, if present
input_prefix_str = prefix;
if (input_prefix_str.rfind(".colvars.state") != std::string::npos) {
input_prefix_str.erase(input_prefix_str.rfind(".colvars.state"),
std::string(".colvars.state").size());
}
return COLVARS_OK;
}
int colvarproxy_io::set_output_prefix(std::string const &prefix)
{
// set input restart name and strip the extension, if present
output_prefix_str = prefix;
if (output_prefix_str.rfind(".colvars.state") != std::string::npos) {
output_prefix_str.erase(output_prefix_str.rfind(".colvars.state"),
std::string(".colvars.state").size());
}
return COLVARS_OK;
}
int colvarproxy_io::set_restart_output_prefix(std::string const &prefix)
{
// set input restart name and strip the extension, if present
restart_output_prefix_str = prefix;
if (restart_output_prefix_str.rfind(".colvars.state") != std::string::npos) {
restart_output_prefix_str.erase(restart_output_prefix_str.rfind(".colvars.state"),
std::string(".colvars.state").size());
}
return COLVARS_OK;
}
int colvarproxy_io::set_default_restart_frequency(int freq)
{
// TODO check for compatibility with colvarsRestartFrequency
restart_frequency_engine = freq;
return COLVARS_OK;
}
std::istream &colvarproxy_io::input_stream(std::string const &input_name, std::istream &colvarproxy_io::input_stream(std::string const &input_name,
std::string const description, std::string const description,
bool error_on_fail) bool error_on_fail)
@ -162,14 +208,19 @@ std::istream &colvarproxy_io::input_stream(std::string const &input_name,
} }
if (colvarproxy_io::input_stream_exists(input_name)) { if (colvarproxy_io::input_stream_exists(input_name)) {
return *(input_streams_[input_name]); std::ifstream *ifs =
dynamic_cast<std::ifstream *>(input_streams_[input_name]);
if (ifs && !ifs->is_open()) {
// This file was opened before, re-open it. Using std::ios::binary to
// work around differences in line termination conventions
// See https://github.com/Colvars/colvars/commit/8236879f7de4
ifs->open(input_name.c_str(), std::ios::binary);
}
} else {
input_streams_[input_name] = new std::ifstream(input_name.c_str(),
std::ios::binary);
} }
// Using binary to work around differences in line termination conventions
// See https://github.com/Colvars/colvars/commit/8236879f7de4
input_streams_[input_name] = new std::ifstream(input_name.c_str(),
std::ios::binary);
if (input_streams_[input_name]->fail() && error_on_fail) { if (input_streams_[input_name]->fail() && error_on_fail) {
cvm::error("Error: cannot open "+description+" \""+input_name+"\".\n", cvm::error("Error: cannot open "+description+" \""+input_name+"\".\n",
COLVARS_FILE_ERROR); COLVARS_FILE_ERROR);
@ -179,6 +230,41 @@ std::istream &colvarproxy_io::input_stream(std::string const &input_name,
} }
std::istream &
colvarproxy_io::input_stream_from_string(std::string const &input_name,
std::string const &content,
std::string const description)
{
if (!io_available()) {
cvm::error("Error: trying to access an input file/channel "
"from the wrong thread.\n", COLVARS_BUG_ERROR);
return *input_stream_error_;
}
if (colvarproxy_io::input_stream_exists(input_name)) {
std::istringstream *iss =
dynamic_cast<std::istringstream *>(input_streams_[input_name]);
if (iss) {
// If there is already a stringstream, replace it
delete iss;
} else {
std::ifstream *ifs =
dynamic_cast<std::ifstream *>(input_streams_[input_name]);
if (ifs) {
if (ifs->is_open()) {
ifs->close();
}
}
}
}
input_streams_[input_name] = new std::istringstream(content);
return *(input_streams_[input_name]);
}
bool colvarproxy_io::input_stream_exists(std::string const &input_name) bool colvarproxy_io::input_stream_exists(std::string const &input_name)
{ {
return (input_streams_.count(input_name) > 0); return (input_streams_.count(input_name) > 0);
@ -188,7 +274,38 @@ bool colvarproxy_io::input_stream_exists(std::string const &input_name)
int colvarproxy_io::close_input_stream(std::string const &input_name) int colvarproxy_io::close_input_stream(std::string const &input_name)
{ {
if (colvarproxy_io::input_stream_exists(input_name)) { if (colvarproxy_io::input_stream_exists(input_name)) {
delete input_streams_[input_name]; std::ifstream *ifs = dynamic_cast<std::ifstream *>(input_streams_[input_name]);
if (ifs) {
if (ifs->is_open()) {
ifs->close();
}
} else {
// From a string, just rewind to the begining
std::istringstream * iss = dynamic_cast<std::istringstream *>(input_streams_[input_name]);
if (iss) {
iss->clear();
iss->seekg(0);
}
}
return COLVARS_OK;
}
return cvm::error("Error: input file/channel \""+input_name+
"\" does not exist.\n", COLVARS_FILE_ERROR);
}
int colvarproxy_io::delete_input_stream(std::string const &input_name)
{
if (colvarproxy_io::close_input_stream(input_name) == COLVARS_OK) {
std::ifstream *ifs = dynamic_cast<std::ifstream *>(input_streams_[input_name]);
if (ifs) {
delete ifs;
} else {
std::istringstream * iss = dynamic_cast<std::istringstream *>(input_streams_[input_name]);
if (iss) {
delete iss;
}
}
input_streams_.erase(input_name); input_streams_.erase(input_name);
return COLVARS_OK; return COLVARS_OK;
} }
@ -199,7 +316,8 @@ int colvarproxy_io::close_input_stream(std::string const &input_name)
int colvarproxy_io::close_input_streams() int colvarproxy_io::close_input_streams()
{ {
for (std::map<std::string, std::istream *>::iterator ii = input_streams_.begin(); for (std::map<std::string,
std::istream *>::iterator ii = input_streams_.begin();
ii != input_streams_.end(); ii != input_streams_.end();
ii++) { ii++) {
delete ii->second; delete ii->second;
@ -209,6 +327,19 @@ int colvarproxy_io::close_input_streams()
} }
std::list<std::string> colvarproxy_io::list_input_stream_names() const
{
std::list<std::string> result;
for (std::map<std::string,
std::istream *>::const_iterator ii = input_streams_.begin();
ii != input_streams_.end();
ii++) {
result.push_back(ii->first);
}
return result;
}
std::ostream & colvarproxy_io::output_stream(std::string const &output_name, std::ostream & colvarproxy_io::output_stream(std::string const &output_name,
std::string const description) std::string const description)
{ {
@ -228,7 +359,7 @@ std::ostream & colvarproxy_io::output_stream(std::string const &output_name,
backup_file(output_name.c_str()); backup_file(output_name.c_str());
output_streams_[output_name] = new std::ofstream(output_name.c_str()); output_streams_[output_name] = new std::ofstream(output_name.c_str(), std::ios::binary);
if (!*(output_streams_[output_name])) { if (!*(output_streams_[output_name])) {
cvm::error("Error: cannot write to "+description+" \""+output_name+"\".\n", cvm::error("Error: cannot write to "+description+" \""+output_name+"\".\n",
COLVARS_FILE_ERROR); COLVARS_FILE_ERROR);
@ -303,6 +434,7 @@ int colvarproxy_io::close_output_streams()
osi != output_streams_.end(); osi != output_streams_.end();
osi++) { osi++) {
(dynamic_cast<std::ofstream *>(osi->second))->close(); (dynamic_cast<std::ofstream *>(osi->second))->close();
delete osi->second;
} }
output_streams_.clear(); output_streams_.clear();

View File

@ -10,9 +10,10 @@
#ifndef COLVARPROXY_IO_H #ifndef COLVARPROXY_IO_H
#define COLVARPROXY_IO_H #define COLVARPROXY_IO_H
#include <iosfwd>
#include <list>
#include <map> #include <map>
#include <string> #include <string>
#include <iosfwd>
/// Methods for data input/output /// Methods for data input/output
@ -66,57 +67,80 @@ public:
} }
/// Prefix of the input state file to be read next /// Prefix of the input state file to be read next
inline std::string & input_prefix() inline std::string const & input_prefix() const
{ {
return input_prefix_str; return input_prefix_str;
} }
/// Initialize input_prefix (NOTE: it will be erased after state file is read)
virtual int set_input_prefix(std::string const &prefix);
/// Default prefix to be used for all output files (final configuration) /// Default prefix to be used for all output files (final configuration)
inline std::string & output_prefix() inline std::string const & output_prefix() const
{ {
return output_prefix_str; return output_prefix_str;
} }
/// Set default output prefix
virtual int set_output_prefix(std::string const &prefix);
/// Prefix of the restart (checkpoint) file to be written next /// Prefix of the restart (checkpoint) file to be written next
inline std::string & restart_output_prefix() inline std::string const & restart_output_prefix() const
{ {
return restart_output_prefix_str; return restart_output_prefix_str;
} }
/// Set default restart state file prefix
virtual int set_restart_output_prefix(std::string const &prefix);
/// Default restart frequency (as set by the simulation engine) /// Default restart frequency (as set by the simulation engine)
inline int default_restart_frequency() const inline int default_restart_frequency() const
{ {
return restart_frequency_engine; return restart_frequency_engine;
} }
/// Buffer from which the input state information may be read /// Communicate/set the restart frequency of the simulation engine
inline char const * & input_buffer() virtual int set_default_restart_frequency(int freq);
{
return input_buffer_; // The input stream functions below are not virtual, because they currently
} // rely on the fact that either std::ifstream or std::istringstream is used
/// Returns a reference to given input stream, creating it if needed /// Returns a reference to given input stream, creating it if needed
/// \param input_name File name (later only a handle) /// \param input_name File name (later only a handle)
/// \param description Purpose of the file /// \param description Purpose of the file
/// \param error_on_fail Raise error when failing to open (allow testing) /// \param error_on_fail Raise error when failing to open (allow testing)
virtual std::istream &input_stream(std::string const &input_name, std::istream & input_stream(std::string const &input_name,
std::string const description = "file/channel", std::string const description = "file/channel",
bool error_on_fail = true); bool error_on_fail = true);
/// Returns a reference to given input stream, creating it if needed
/// \param input_name Identifier of the input stream
/// \param content Set this string as the stream's buffer
/// \param description Purpose of the stream
std::istream & input_stream_from_string(std::string const &input_name,
std::string const &content,
std::string const description = "string");
/// Check if the file/channel is open (without opening it if not) /// Check if the file/channel is open (without opening it if not)
virtual bool input_stream_exists(std::string const &input_name); bool input_stream_exists(std::string const &input_name);
/// Closes the given input stream /// Closes the given input stream
virtual int close_input_stream(std::string const &input_name); int close_input_stream(std::string const &input_name);
/// Closes all input streams /// Closes all input streams
virtual int close_input_streams(); int close_input_streams();
/// Same as close_input_stream(), but also removes the corresponding entry from memory
int delete_input_stream(std::string const &input_name);
/// List all input streams that were opened at some point
std::list<std::string> list_input_stream_names() const;
/// Returns a reference to the named output file/channel (open it if needed) /// Returns a reference to the named output file/channel (open it if needed)
/// \param output_name File name or identifier /// \param output_name File name or identifier
/// \param description Purpose of the file /// \param description Purpose of the file
virtual std::ostream &output_stream(std::string const &output_name, virtual std::ostream &output_stream(std::string const &output_name,
std::string const description = "file/channel"); std::string const description);
/// Check if the file/channel is open (without opening it if not) /// Check if the file/channel is open (without opening it if not)
virtual bool output_stream_exists(std::string const &output_name); virtual bool output_stream_exists(std::string const &output_name);
@ -158,9 +182,6 @@ protected:
/// Object whose reference is returned when write errors occur /// Object whose reference is returned when write errors occur
std::ostream *output_stream_error_; std::ostream *output_stream_error_;
/// Buffer from which the input state information may be read
char const *input_buffer_;
}; };

View File

@ -18,6 +18,7 @@ colvarproxy_system::colvarproxy_system()
{ {
angstrom_value_ = 0.0; angstrom_value_ = 0.0;
kcal_mol_value_ = 0.0; kcal_mol_value_ = 0.0;
timestep_ = 1.0;
target_temperature_ = 0.0; target_temperature_ = 0.0;
boltzmann_ = 0.001987191; // Default: kcal/mol/K boltzmann_ = 0.001987191; // Default: kcal/mol/K
boundaries_type = boundaries_unsupported; boundaries_type = boundaries_unsupported;
@ -46,10 +47,10 @@ int colvarproxy_system::set_target_temperature(cvm::real T)
} }
cvm::real colvarproxy_system::dt() int colvarproxy_system::set_integration_timestep(cvm::real dt)
{ {
// TODO define, document and implement a user method to set the value of this timestep_ = dt;
return 1.0; return COLVARS_OK;
} }

View File

@ -61,8 +61,14 @@ public:
/// Set the current target temperature of the simulation (K units) /// Set the current target temperature of the simulation (K units)
virtual int set_target_temperature(cvm::real T); virtual int set_target_temperature(cvm::real T);
/// \brief Time step of the simulation (fs) /// Time step of the simulation (fs units)
virtual cvm::real dt(); inline double dt() const
{
return timestep_;
}
/// Set the current integration timestep of the simulation (fs units)
virtual int set_integration_timestep(cvm::real dt);
/// \brief Pseudo-random number with Gaussian distribution /// \brief Pseudo-random number with Gaussian distribution
virtual cvm::real rand_gaussian(void); virtual cvm::real rand_gaussian(void);
@ -137,9 +143,12 @@ protected:
/// Boltzmann constant in internal Colvars units /// Boltzmann constant in internal Colvars units
cvm::real boltzmann_; cvm::real boltzmann_;
/// Most up to date target temperature for the system (in K) /// Most up to date target temperature (K units); default to 0.0 if undefined
cvm::real target_temperature_; cvm::real target_temperature_;
/// Current integration timestep (engine units); default to 1.0 if undefined
double timestep_;
/// \brief Value of 1 Angstrom in the internal (front-end) Colvars unit for atomic coordinates /// \brief Value of 1 Angstrom in the internal (front-end) Colvars unit for atomic coordinates
/// * defaults to 0 in the base class; derived proxy classes must set it /// * defaults to 0 in the base class; derived proxy classes must set it
/// * in VMD proxy, can only be changed when no variables are defined /// * in VMD proxy, can only be changed when no variables are defined

View File

@ -83,7 +83,7 @@ int colvarproxy_tcl::tcl_run_file(std::string const &fileName)
Tcl_Interp *const interp = get_tcl_interp(); Tcl_Interp *const interp = get_tcl_interp();
int err = Tcl_EvalFile(interp, fileName.c_str()); int err = Tcl_EvalFile(interp, fileName.c_str());
if (err != TCL_OK) { if (err != TCL_OK) {
cvm::log("Error while executing Tcl script file" + fileName + ":\n"); cvm::log("Error while executing Tcl script file \"" + fileName + "\":\n");
cvm::error(Tcl_GetStringResult(interp)); cvm::error(Tcl_GetStringResult(interp));
return COLVARS_ERROR; return COLVARS_ERROR;
} }

View File

@ -21,7 +21,7 @@ colvarproxy_volmaps::colvarproxy_volmaps()
colvarproxy_volmaps::~colvarproxy_volmaps() {} colvarproxy_volmaps::~colvarproxy_volmaps() {}
int colvarproxy_volmaps::volmaps_available() int colvarproxy_volmaps::check_volmaps_available()
{ {
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
} }

View File

@ -18,8 +18,8 @@ public:
/// Clear volumetric map data /// Clear volumetric map data
int reset(); int reset();
/// \brief Whether this implementation has capability to use volumetric maps /// Test whether this implementation can use volumetric maps as CVs
virtual int volmaps_available(); virtual int check_volmaps_available();
/// Create a slot for a volumetric map not requested yet /// Create a slot for a volumetric map not requested yet
int add_volmap_slot(int volmap_id); int add_volmap_slot(int volmap_id);

View File

@ -0,0 +1,102 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvartypes.h"
#include "colvarvalue.h"
#include "colvars_memstream.h"
bool cvm::memory_stream::expand_output_buffer(size_t add_bytes)
{
auto &buffer = external_output_buffer_ ? *external_output_buffer_ : internal_buffer_;
if ((buffer.size() + add_bytes) <= max_length_) {
buffer.resize((buffer.size() + add_bytes));
} else {
setstate(std::ios::badbit);
}
return bool(*this);
}
template <> void cvm::memory_stream::write_object(std::string const &t)
{
size_t const string_length = t.size();
size_t const new_data_size = sizeof(size_t) + sizeof(char) * string_length;
if (expand_output_buffer(new_data_size)) {
std::memcpy(output_location(), &string_length, sizeof(size_t));
incr_write_pos(sizeof(size_t));
std::memcpy(output_location(), t.c_str(), t.size() * sizeof(char));
incr_write_pos(t.size() * sizeof(char));
}
}
template <> cvm::memory_stream &operator<<(cvm::memory_stream &os, std::string const &t)
{
os.write_object<std::string>(t);
return os;
}
template <> void cvm::memory_stream::write_object(colvarvalue const &t)
{
*this << t;
}
template <> void cvm::memory_stream::write_object(cvm::vector1d<cvm::real> const &t)
{
return write_vector<cvm::real>(t.data_array());
}
template <>
cvm::memory_stream &operator<<(cvm::memory_stream &os, cvm::vector1d<cvm::real> const &t)
{
os.write_vector<cvm::real>(t.data_array());
return os;
}
template <> void cvm::memory_stream::read_object(std::string &t)
{
begin_reading();
size_t string_length = 0;
if (has_remaining(sizeof(size_t))) {
std::memcpy(&string_length, input_location(), sizeof(size_t));
incr_read_pos(sizeof(size_t));
if (has_remaining(string_length * sizeof(char))) {
t.assign(reinterpret_cast<char const *>(input_location()), string_length);
incr_read_pos(string_length * sizeof(char));
done_reading();
} else {
setstate(std::ios::failbit);
}
}
}
template <> cvm::memory_stream &operator>>(cvm::memory_stream &is, std::string &t)
{
is.read_object<std::string>(t);
return is;
}
template <> void cvm::memory_stream::read_object(colvarvalue &t)
{
*this >> t;
}
template <> void cvm::memory_stream::read_object(cvm::vector1d<cvm::real> &t)
{
return read_vector<cvm::real>(t.data_array());
}
template <> cvm::memory_stream &operator>>(cvm::memory_stream &is, cvm::vector1d<cvm::real> &t)
{
is.read_vector<cvm::real>(t.data_array());
return is;
}

View File

@ -0,0 +1,289 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef MEMORY_STREAM_H
#define MEMORY_STREAM_H
#include <cstring>
#include <string>
#include <typeinfo>
#include <vector>
#include <iomanip>
// Work around missing std::is_trivially_copyable in old GCC and Clang versions
// TODO remove this after CentOS 7 has been beyond EOL for a while
#if (defined(__GNUC__) && (__GNUC__ < 5) && !defined(__clang__)) || (defined(__clang__) && (__clang_major__ < 7))
// Clang needs an exception, because it defines __GNUC__ as well
#define IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
#else
#define IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
#endif
class cvm::memory_stream {
public:
/// Set up an empty stream with an internal buffer, suitable for writing to
/// \param max_length Maximum allowed capacity (default is 64 GiB)
memory_stream(size_t max_length = (static_cast<size_t>(1L) << 36)) : max_length_(max_length) {}
/// Set up a stream based on an external input buffer
memory_stream(size_t n, unsigned char const *buf)
: external_input_buffer_(buf), internal_buffer_(), data_length_(n), max_length_(data_length_)
{
}
/// Set up a stream based on an external output buffer
memory_stream(std::vector<unsigned char> &buf) : memory_stream()
{
external_output_buffer_ = &buf;
}
/// Length of the buffer
inline size_t length() const { return data_length_; }
/// Output buffer
inline unsigned char *output_buffer()
{
return (external_output_buffer_ ? external_output_buffer_->data() : internal_buffer_.data());
}
/// Next location to write to
inline unsigned char *output_location() { return output_buffer() + data_length_; }
/// Input buffer
inline unsigned char const *input_buffer() const
{
return (external_input_buffer_ ? external_input_buffer_ : internal_buffer_.data());
}
/// Next location to read from
inline unsigned char const *input_location() const { return input_buffer() + read_pos_; }
/// Cast operator to be used to test for errors
inline explicit operator bool() const { return state_ == std::ios::goodbit; }
/// Write a simple object to the output buffer
template <typename T> void write_object(T const &t);
/// Wrapper to write_object()
template <typename T> friend memory_stream &operator<<(memory_stream &os, T const &t);
/// Write a vector of simple objects to the output buffer
template <typename T> void write_vector(std::vector<T> const &t);
/// Wrapper to write_vector()
template <typename T>
friend memory_stream &operator<<(memory_stream &os, std::vector<T> const &t);
/// Read a simple object from the buffer
template <typename T> void read_object(T &t);
/// Wrapper to read_object()
template <typename T> friend memory_stream &operator>>(memory_stream &is, T &t);
/// Read a vector of simple objects from the buffer
template <typename T> void read_vector(std::vector<T> &t);
/// Wrapper to read_vector()
template <typename T> friend memory_stream &operator>>(memory_stream &is, std::vector<T> &t);
// Compatibility with STL stream functions
/// Report the current position in the buffer
inline size_t tellg() const { return read_pos_; }
/// Report the current position in the buffer
inline memory_stream & seekg(size_t pos) { read_pos_ = pos; return *this; }
/// Ignore formatting operators
inline void setf(decltype(std::ios::fmtflags(0)), decltype(std::ios::floatfield)) {}
/// Ignore formatting operators
inline void flags(decltype(std::ios::fmtflags(0))) {}
/// Get the current formatting flags (i.e. none because this stream is unformatted)
inline decltype(std::ios::fmtflags(0)) flags() const { return std::ios::fmtflags(0); }
/// Get the error code
inline std::ios::iostate rdstate() const { return state_; }
/// Set the error code
inline void setstate(std::ios::iostate new_state) { state_ |= new_state; }
/// Clear the error code
inline void clear() { state_ = std::ios::goodbit; }
protected:
/// External output buffer
std::vector<unsigned char> *external_output_buffer_ = nullptr;
/// External input buffer
unsigned char const *external_input_buffer_ = nullptr;
/// Internal buffer (may server for both input and output)
std::vector<unsigned char> internal_buffer_;
/// Length of the data buffer (either internal or external)
size_t data_length_ = 0L;
/// Largest allowed capacity of the data buffer
size_t const max_length_;
/// Error status
std::ios::iostate state_ = std::ios::goodbit;
/// Add the requester number of bytes to the array capacity; return false if buffer is external
bool expand_output_buffer(size_t add_bytes);
/// Move the buffer position past the data just written
inline void incr_write_pos(size_t c) { data_length_ += c; }
/// Current position when reading from the buffer
size_t read_pos_ = 0L;
/// Begin an attempt to read an object; assume EOF unless there is space remaining
inline void begin_reading() { setstate(std::ios::eofbit); }
/// Mark the reading attempt succesful
inline void done_reading() { clear(); }
/// Move the buffer position past the data just read
inline void incr_read_pos(size_t c) { read_pos_ += c; }
/// Check that the buffer contains enough bytes to read as the argument says, set error
/// otherwise
inline bool has_remaining(size_t c) { return c <= (data_length_ - read_pos_); }
};
template <typename T> void cvm::memory_stream::write_object(T const &t)
{
static_assert(IS_TRIVIALLY_COPYABLE(T), "Cannot use write_object() on complex type");
size_t const new_data_size = sizeof(T);
if (expand_output_buffer(new_data_size)) {
std::memcpy(output_location(), &t, sizeof(T));
incr_write_pos(new_data_size);
}
}
template <typename T> cvm::memory_stream &operator<<(cvm::memory_stream &os, T const &t)
{
os.write_object<T>(t);
return os;
}
template <typename T> void cvm::memory_stream::write_vector(std::vector<T> const &t)
{
static_assert(IS_TRIVIALLY_COPYABLE(T), "Cannot use write_vector() on complex type");
size_t const vector_length = t.size();
size_t const new_data_size = sizeof(size_t) + sizeof(T) * vector_length;
if (expand_output_buffer(new_data_size)) {
std::memcpy(output_location(), &vector_length, sizeof(size_t));
incr_write_pos(sizeof(T));
std::memcpy(output_location(), t.data(), t.size() * sizeof(T));
incr_write_pos(t.size() * sizeof(T));
}
}
template <typename T>
cvm::memory_stream &operator<<(cvm::memory_stream &os, std::vector<T> const &t)
{
os.write_vector<T>(t);
return os;
}
template <typename T> void cvm::memory_stream::read_object(T &t)
{
static_assert(IS_TRIVIALLY_COPYABLE(T), "Cannot use read_object() on complex type");
begin_reading();
if (has_remaining(sizeof(T))) {
std::memcpy(&t, input_location(), sizeof(T));
incr_read_pos(sizeof(T));
done_reading();
}
}
template <typename T> cvm::memory_stream &operator>>(cvm::memory_stream &is, T &t)
{
is.read_object<T>(t);
return is;
}
template <typename T> void cvm::memory_stream::read_vector(std::vector<T> &t)
{
static_assert(IS_TRIVIALLY_COPYABLE(T), "Cannot use read_vector() on complex type");
begin_reading();
size_t vector_length = 0;
if (has_remaining(sizeof(size_t))) {
std::memcpy(&vector_length, input_location(), sizeof(size_t));
incr_read_pos(sizeof(size_t));
if (has_remaining(vector_length * sizeof(T))) {
t.resize(vector_length);
std::memcpy(t.data(), input_location(), vector_length * sizeof(T));
incr_read_pos(vector_length * sizeof(T));
done_reading();
} else {
setstate(std::ios::failbit);
}
}
}
template <typename T> cvm::memory_stream &operator>>(cvm::memory_stream &is, std::vector<T> &t)
{
is.read_vector<T>(t);
return is;
}
template <typename T> cvm::memory_stream &operator<<(cvm::memory_stream &os,
decltype(std::setprecision(10)) const &)
{
return os;
}
#if !defined(_MSC_VER) && !defined(__SUNPRO_CC)
// Visual Studio and MSVC use the same return type for both modifiers
template <typename T> cvm::memory_stream &operator<<(cvm::memory_stream &os,
decltype(std::setw(10)) const &)
{
return os;
}
#endif
// Declare specializations
template <> void cvm::memory_stream::write_object(std::string const &t);
template <> cvm::memory_stream &operator<<(cvm::memory_stream &os, std::string const &t);
template <> void cvm::memory_stream::write_object(colvarvalue const &t);
template <> cvm::memory_stream &operator<<(cvm::memory_stream &os, colvarvalue const &x);
template <> void cvm::memory_stream::write_object(cvm::vector1d<cvm::real> const &t);
template <>
cvm::memory_stream &operator<<(cvm::memory_stream &os, cvm::vector1d<cvm::real> const &t);
template <> void cvm::memory_stream::read_object(std::string &t);
template <> cvm::memory_stream &operator>>(cvm::memory_stream &is, std::string &t);
template <> void cvm::memory_stream::read_object(colvarvalue &t);
template <> cvm::memory_stream &operator>>(cvm::memory_stream &is, colvarvalue &t);
template <> void cvm::memory_stream::read_object(cvm::vector1d<cvm::real> &t);
template <> cvm::memory_stream &operator>>(cvm::memory_stream &is, cvm::vector1d<cvm::real> &t);
#endif

View File

@ -1,3 +1,3 @@
#ifndef COLVARS_VERSION #ifndef COLVARS_VERSION
#define COLVARS_VERSION "2023-05-01" #define COLVARS_VERSION "2024-06-04"
#endif #endif

View File

@ -7,8 +7,6 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <cstdlib>
#include <cstring>
#include <sstream> #include <sstream>
#include "colvarproxy.h" #include "colvarproxy.h"
@ -35,6 +33,7 @@ colvarscript::colvarscript(colvarproxy *p, colvarmodule *m)
: proxy_(p), : proxy_(p),
colvars(m) colvars(m)
{ {
cmdline_main_cmd_ = std::string("cv");
cmd_names = NULL; cmd_names = NULL;
init_commands(); init_commands();
#ifdef COLVARS_TCL #ifdef COLVARS_TCL
@ -141,7 +140,7 @@ int colvarscript::init_command(colvarscript::command const &comm,
} }
cmd_full_help[comm] = cmd_help[comm]+"\n"; cmd_full_help[comm] = cmd_help[comm]+"\n";
if (cmd_n_args_min[comm] > 0) { if (cmd_n_args_max[comm] > 0) {
cmd_full_help[comm] += "\nParameters\n"; cmd_full_help[comm] += "\nParameters\n";
cmd_full_help[comm] += "----------\n\n"; cmd_full_help[comm] += "----------\n\n";
size_t i; size_t i;
@ -281,11 +280,15 @@ std::string colvarscript::get_command_cmdline_syntax(colvarscript::Object_type t
switch (t) { switch (t) {
case use_module: case use_module:
return std::string("cv "+cmdline_cmd+cmdline_args); break; return std::string(cmdline_main_cmd_ + " " + cmdline_cmd + cmdline_args);
break;
case use_colvar: case use_colvar:
return std::string("cv colvar name "+cmdline_cmd+cmdline_args); break; return std::string(cmdline_main_cmd_ + " colvar name " + cmdline_cmd+
cmdline_args);
break;
case use_bias: case use_bias:
return std::string("cv bias name "+cmdline_cmd+cmdline_args); break; return std::string(cmdline_main_cmd_ + " bias name " + cmdline_cmd+cmdline_args);
break;
default: default:
// Already handled, but silence the warning // Already handled, but silence the warning
return std::string(""); return std::string("");
@ -353,7 +356,7 @@ int colvarscript::run(int objc, unsigned char *const objv[])
} }
if (objc < 2) { if (objc < 2) {
set_result_str("No commands given: use \"cv help\" " set_result_str("No commands given: use \""+cmdline_main_cmd_+" help\" "
"for a list of commands."); "for a list of commands.");
return COLVARSCRIPT_ERROR; return COLVARSCRIPT_ERROR;
} }
@ -436,7 +439,8 @@ int colvarscript::run(int objc, unsigned char *const objv[])
error_code = (*cmd_fn)(obj_for_cmd, objc, objv); error_code = (*cmd_fn)(obj_for_cmd, objc, objv);
} else { } else {
add_error_msg("Syntax error: "+cmdline+"\n" add_error_msg("Syntax error: "+cmdline+"\n"
" Run \"cv help\" or \"cv help <command>\" " " Run \""+main_cmd+" help\" or \""+
main_cmd+" help <command>\" "
"to get the correct syntax.\n"); "to get the correct syntax.\n");
error_code = COLVARSCRIPT_ERROR; error_code = COLVARSCRIPT_ERROR;
} }
@ -763,7 +767,7 @@ extern "C" int tcl_run_colvarscript_command(ClientData /* clientData */,
int colvarscript::set_result_text_from_str(std::string const &x_str, int colvarscript::set_result_text_from_str(std::string const &x_str,
unsigned char *obj) { unsigned char *obj) {
if (obj) { if (obj) {
strcpy(reinterpret_cast<char *>(obj), x_str.c_str()); std::memcpy(reinterpret_cast<char *>(obj), x_str.c_str(), x_str.size());
} else { } else {
set_result_str(x_str); set_result_str(x_str);
} }

View File

@ -16,7 +16,6 @@
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvarbias.h"
#include "colvarproxy.h" #include "colvarproxy.h"
@ -25,6 +24,8 @@
#define COLVARSCRIPT_OK 0 #define COLVARSCRIPT_OK 0
class colvardeps;
class colvarscript { class colvarscript {
private: private:
@ -161,6 +162,11 @@ public:
/// \param cmd Name of the command's function (e.g. "cv_units") /// \param cmd Name of the command's function (e.g. "cv_units")
int get_command_n_args_max(char const *cmd); int get_command_n_args_max(char const *cmd);
/// Set the main command for the CLI, when it is not "cv" (e.g. LAMMPS)
inline void set_cmdline_main_cmd(std::string const &cmd) {
cmdline_main_cmd_ = cmd;
}
/// Get help string for a command (does not specify how it is launched) /// Get help string for a command (does not specify how it is launched)
/// \param cmd Name of the command's function (e.g. "cv_units") /// \param cmd Name of the command's function (e.g. "cv_units")
char const *get_command_full_help(char const *cmd); char const *get_command_full_help(char const *cmd);
@ -263,6 +269,9 @@ private: // TODO
/// Internal identifiers of command strings /// Internal identifiers of command strings
std::map<std::string, command> cmd_str_map; std::map<std::string, command> cmd_str_map;
/// Main command used in command line ("cv" by default)
std::string cmdline_main_cmd_;
/// Inverse of cmd_str_map (to be exported outside this class) /// Inverse of cmd_str_map (to be exported outside this class)
char const **cmd_names; char const **cmd_names;

View File

@ -8,9 +8,9 @@
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <vector> #include <vector>
#include <cstdlib>
#include <string.h>
#include "colvar.h"
#include "colvarbias.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvardeps.h" #include "colvardeps.h"
#include "colvarscript.h" #include "colvarscript.h"

View File

@ -47,14 +47,10 @@
// If CVSCRIPT is not defined, this file yields the function prototypes // If CVSCRIPT is not defined, this file yields the function prototypes
#ifndef CVSCRIPT #ifndef CVSCRIPT
#ifdef __cplusplus
#define CVSCRIPT_COMM_PROTO(COMM) \ #define CVSCRIPT_COMM_PROTO(COMM) \
extern "C" int CVSCRIPT_COMM_FNAME(COMM)(void *, \ extern "C" int CVSCRIPT_COMM_FNAME(COMM)(void *, \
int, unsigned char *const *); int, \
#else unsigned char *const *);
#define CVSCRIPT_COMM_PROTO(COMM) \
int CVSCRIPT_COMM_FNAME(COMM)(void *, int, unsigned char *const *);
#endif
#define CVSCRIPT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS,FN_BODY) \ #define CVSCRIPT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS,FN_BODY) \
CVSCRIPT_COMM_PROTO(COMM) CVSCRIPT_COMM_PROTO(COMM)
@ -454,7 +450,8 @@ CVSCRIPT(cv_listcommands,
) )
CVSCRIPT(cv_listindexfiles, CVSCRIPT(cv_listindexfiles,
"Get a list of the index files loaded in this session", "Get a list of the index files loaded in this session\n"
"list : sequence of strings - List of index file names",
0, 0, 0, 0,
"", "",
int const n_files = script->module()->index_file_names.size(); int const n_files = script->module()->index_file_names.size();
@ -467,19 +464,36 @@ CVSCRIPT(cv_listindexfiles,
return COLVARS_OK; return COLVARS_OK;
) )
CVSCRIPT(cv_listinputfiles,
"Get a list of all input/configuration files loaded in this session\n"
"list : sequence of strings - List of file names",
0, 0,
"",
std::list<std::string> const l =
script->proxy()->list_input_stream_names();
std::string result;
for (std::list<std::string>::const_iterator li = l.begin();
li != l.end(); li++) {
if (li != l.begin()) result.append(1, ' ');
result.append(*li);
}
script->set_result_str(result);
return COLVARS_OK;
)
CVSCRIPT(cv_load, CVSCRIPT(cv_load,
"Load data from a state file into all matching colvars and biases", "Load data from a state file into all matching colvars and biases",
1, 1, 1, 1,
"prefix : string - Path to existing state file or input prefix", "prefix : string - Path to existing state file or input prefix",
char const *arg = char const *arg =
script->obj_to_str(script->get_module_cmd_arg(0, objc, objv)); script->obj_to_str(script->get_module_cmd_arg(0, objc, objv));
script->proxy()->input_prefix() = cvm::state_file_prefix(arg); int error_code =
if (script->module()->setup_input() == COLVARS_OK) { script->proxy()->set_input_prefix(cvm::state_file_prefix(arg));
return COLVARS_OK; error_code |= script->module()->setup_input();
} else { if (error_code != COLVARS_OK) {
script->add_error_msg("Error loading state file"); script->add_error_msg("Error loading state file");
return COLVARSCRIPT_ERROR;
} }
return error_code;
) )
CVSCRIPT(cv_loadfromstring, CVSCRIPT(cv_loadfromstring,
@ -488,7 +502,8 @@ CVSCRIPT(cv_loadfromstring,
"buffer : string - String buffer containing the state information", "buffer : string - String buffer containing the state information",
char const *arg = char const *arg =
script->obj_to_str(script->get_module_cmd_arg(0, objc, objv)); script->obj_to_str(script->get_module_cmd_arg(0, objc, objv));
script->proxy()->input_buffer() = arg; script->proxy()->input_stream_from_string("input state string",
std::string(arg));
if (script->module()->setup_input() == COLVARS_OK) { if (script->module()->setup_input() == COLVARS_OK) {
return COLVARS_OK; return COLVARS_OK;
} else { } else {
@ -560,8 +575,7 @@ CVSCRIPT(cv_save,
"prefix : string - Output prefix with trailing \".colvars.state\" gets removed)", "prefix : string - Output prefix with trailing \".colvars.state\" gets removed)",
std::string const prefix = std::string const prefix =
cvm::state_file_prefix(script->obj_to_str(script->get_module_cmd_arg(0, objc, objv))); cvm::state_file_prefix(script->obj_to_str(script->get_module_cmd_arg(0, objc, objv)));
script->proxy()->output_prefix() = prefix; int error_code = script->proxy()->set_output_prefix(prefix);
int error_code = COLVARS_OK;
error_code |= script->module()->setup_output(); error_code |= script->module()->setup_output();
error_code |= script->module()->write_restart_file(prefix+ error_code |= script->module()->write_restart_file(prefix+
".colvars.state"); ".colvars.state");
@ -578,10 +592,10 @@ CVSCRIPT(cv_savetostring,
) )
CVSCRIPT(cv_targettemperature, CVSCRIPT(cv_targettemperature,
"Get/set target temperature, overriding what the MD engine provides\n" "Get/set target temperature, overriding internally what the MD engine reports\n"
"T : float - Current target temperature in K", "T : float - Current target temperature in K",
0, 1, 0, 1,
"T : float - New target temperature in K", "T : float - New target temperature in K (internal use)",
char const *Targ = char const *Targ =
script->obj_to_str(script->get_module_cmd_arg(0, objc, objv)); script->obj_to_str(script->get_module_cmd_arg(0, objc, objv));
if (Targ == NULL) { if (Targ == NULL) {
@ -591,6 +605,20 @@ CVSCRIPT(cv_targettemperature,
} }
) )
CVSCRIPT(cv_timestep,
"Get/set integration timestep, overriding internally what the MD engine reports\n"
"dt : float - Current integration timestep in MD engine units",
0, 1,
"dt : float - New integration timestep in MD engine units",
char const *arg =
script->obj_to_str(script->get_module_cmd_arg(0, objc, objv));
if (arg == NULL) {
return script->set_result_real(script->proxy()->dt());
} else {
return script->proxy()->set_integration_timestep(strtod(arg, NULL));
}
)
CVSCRIPT(cv_units, CVSCRIPT(cv_units,
"Get or set the current Colvars unit system\n" "Get or set the current Colvars unit system\n"
"units : string - The current unit system", "units : string - The current unit system",

View File

@ -9,11 +9,9 @@
#include <vector> #include <vector>
#include <cstdlib>
#include <stdlib.h>
#include <string.h>
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvarbias.h"
#include "colvardeps.h" #include "colvardeps.h"
#include "colvarscript.h" #include "colvarscript.h"
#include "colvarscript_commands.h" #include "colvarscript_commands.h"

View File

@ -9,7 +9,7 @@
CVSCRIPT(bias_bin, CVSCRIPT(bias_bin,
"Get the current grid bin index (1D ABF only for now)\n" "Get the current grid bin index (flattened if more than 1d)\n"
"bin : integer - Bin index", "bin : integer - Bin index",
0, 0, 0, 0,
"", "",
@ -17,6 +17,8 @@ CVSCRIPT(bias_bin,
return COLVARS_OK; return COLVARS_OK;
) )
/// This is deprecated in the context of mwABF; no other known uses
/// But removing it may break user scripts
CVSCRIPT(bias_bincount, CVSCRIPT(bias_bincount,
"Get the number of samples at the given grid bin (1D ABF only for now)\n" "Get the number of samples at the given grid bin (1D ABF only for now)\n"
"samples : integer - Number of samples", "samples : integer - Number of samples",
@ -36,6 +38,25 @@ CVSCRIPT(bias_bincount,
return COLVARS_OK; return COLVARS_OK;
) )
CVSCRIPT(bias_local_sample_count,
"Get the number of samples around the current bin"
"samples : integer - Number of samples",
0, 1,
"radius : integer - Sum over radius bins around current bin",
int radius = 0;
char const *arg =
script->obj_to_str(script->get_bias_cmd_arg(0, objc, objv));
if (arg) {
std::string const param(arg);
if (!(std::istringstream(param) >> radius)) {
script->add_error_msg("local_sample_count: error parsing radius");
return COLVARSCRIPT_ERROR;
}
}
script->set_result_str(cvm::to_str(this_bias->local_sample_count(radius)));
return COLVARS_OK;
)
CVSCRIPT(bias_binnum, CVSCRIPT(bias_binnum,
"Get the total number of grid points of this bias (1D ABF only for now)\n" "Get the total number of grid points of this bias (1D ABF only for now)\n"
"Bins : integer - Number of grid points", "Bins : integer - Number of grid points",

View File

@ -11,8 +11,8 @@
#include <vector> #include <vector>
#include <cstdlib> #include <cstdlib>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "colvar.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvardeps.h" #include "colvardeps.h"
#include "colvarscript.h" #include "colvarscript.h"

View File

@ -9,7 +9,7 @@
CVSCRIPT(colvar_addforce, CVSCRIPT(colvar_addforce,
"Apply the given force onto this colvar and return the same\n" "Apply the given force onto this colvar (no effects outside run)\n"
"force : float or array - Applied force; matches colvar dimensionality", "force : float or array - Applied force; matches colvar dimensionality",
1, 1, 1, 1,
"force : float or array - Applied force; must match colvar dimensionality", "force : float or array - Applied force; must match colvar dimensionality",

View File

@ -7,12 +7,10 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <cstdlib>
#include <cstring>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvartypes.h" #include "colvartypes.h"
#include "colvarparse.h" #include "colvaratoms.h"
#include "colvar_rotation_derivative.h"
#ifdef COLVARS_LAMMPS #ifdef COLVARS_LAMMPS
// Use open-source Jacobi implementation // Use open-source Jacobi implementation
@ -204,14 +202,6 @@ cvm::quaternion::position_derivative_inner(cvm::rvector const &pos,
return result; return result;
} }
// Calculate the optimal rotation between two groups, and implement it
// as a quaternion. Uses the method documented in: Coutsias EA,
// Seok C, Dill KA. Using quaternions to calculate RMSD. J Comput
// Chem. 25(15):1849-57 (2004) DOI: 10.1002/jcc.20110 PubMed: 15376254
#ifdef COLVARS_LAMMPS #ifdef COLVARS_LAMMPS
namespace { namespace {
inline void *new_Jacobi_solver(int size) { inline void *new_Jacobi_solver(int size) {
@ -226,7 +216,7 @@ namespace {
int colvarmodule::rotation::init() int colvarmodule::rotation::init()
{ {
b_debug_gradients = false; b_debug_gradients = false;
lambda = 0.0; // lambda = 0.0;
cvm::main()->cite_feature("Optimal rotation via flexible fitting"); cvm::main()->cite_feature("Optimal rotation via flexible fitting");
return COLVARS_OK; return COLVARS_OK;
} }
@ -300,6 +290,25 @@ void colvarmodule::rotation::build_correlation_matrix(
} }
} }
void colvarmodule::rotation::build_correlation_matrix(
std::vector<cvm::atom> const &pos1,
std::vector<cvm::atom_pos> const &pos2)
{
// build the correlation matrix
size_t i;
for (i = 0; i < pos1.size(); i++) {
C.xx += pos1[i].pos.x * pos2[i].x;
C.xy += pos1[i].pos.x * pos2[i].y;
C.xz += pos1[i].pos.x * pos2[i].z;
C.yx += pos1[i].pos.y * pos2[i].x;
C.yy += pos1[i].pos.y * pos2[i].y;
C.yz += pos1[i].pos.y * pos2[i].z;
C.zx += pos1[i].pos.z * pos2[i].x;
C.zy += pos1[i].pos.z * pos2[i].y;
C.zz += pos1[i].pos.z * pos2[i].z;
}
}
void colvarmodule::rotation::compute_overlap_matrix() void colvarmodule::rotation::compute_overlap_matrix()
{ {
@ -325,28 +334,26 @@ void colvarmodule::rotation::compute_overlap_matrix()
#ifndef COLVARS_LAMMPS #ifndef COLVARS_LAMMPS
namespace { namespace NR {
void diagonalize_matrix(cvm::matrix2d<cvm::real> &m, void diagonalize_matrix(cvm::real m[4][4],
cvm::vector1d<cvm::real> &eigval, cvm::real eigval[4],
cvm::matrix2d<cvm::real> &eigvec) cvm::real eigvec[4][4])
{ {
eigval.resize(4); std::memset(eigval, 0, sizeof(cvm::real) * 4);
eigval.reset(); std::memset(eigvec, 0, sizeof(cvm::real) * 4 * 4);
eigvec.resize(4, 4);
eigvec.reset();
// diagonalize // diagonalize
int jac_nrot = 0; int jac_nrot = 0;
if (NR_Jacobi::jacobi(m.c_array(), eigval.c_array(), eigvec.c_array(), &jac_nrot) != if (NR_Jacobi::jacobi(m, eigval, eigvec, &jac_nrot) !=
COLVARS_OK) { COLVARS_OK) {
cvm::error("Too many iterations in jacobi diagonalization.\n" cvm::error("Too many iterations in jacobi diagonalization.\n"
"This is usually the result of an ill-defined set of atoms for " "This is usually the result of an ill-defined set of atoms for "
"rotational alignment (RMSD, rotateReference, etc).\n"); "rotational alignment (RMSD, rotateReference, etc).\n");
} }
NR_Jacobi::eigsrt(eigval.c_array(), eigvec.c_array()); NR_Jacobi::eigsrt(eigval, eigvec);
// jacobi saves eigenvectors by columns // jacobi saves eigenvectors by columns
NR_Jacobi::transpose(eigvec.c_array()); NR_Jacobi::transpose(eigvec);
// normalize eigenvectors // normalize eigenvectors
for (size_t ie = 0; ie < 4; ie++) { for (size_t ie = 0; ie < 4; ie++) {
@ -375,27 +382,51 @@ void colvarmodule::rotation::calc_optimal_rotation(
C.reset(); C.reset();
build_correlation_matrix(pos1, pos2); build_correlation_matrix(pos1, pos2);
S.resize(4, 4); calc_optimal_rotation_impl();
S.reset();
if (b_debug_gradients) debug_gradients<cvm::atom_pos, cvm::atom_pos>(*this, pos1, pos2);
}
void colvarmodule::rotation::calc_optimal_rotation(
std::vector<cvm::atom> const &pos1,
std::vector<cvm::atom_pos> const &pos2)
{
C.reset();
build_correlation_matrix(pos1, pos2);
calc_optimal_rotation_impl();
if (b_debug_gradients) debug_gradients<cvm::atom, cvm::atom_pos>(*this, pos1, pos2);
}
// Calculate the optimal rotation between two groups, and implement it
// as a quaternion. Uses the method documented in: Coutsias EA,
// Seok C, Dill KA. Using quaternions to calculate RMSD. J Comput
// Chem. 25(15):1849-57 (2004) DOI: 10.1002/jcc.20110 PubMed: 15376254
void colvarmodule::rotation::calc_optimal_rotation_impl() {
compute_overlap_matrix(); compute_overlap_matrix();
S_backup.resize(4, 4); // S_backup = S;
S_backup = S; std::memcpy(&S_backup[0][0], &S, 4*4*sizeof(cvm::real));
if (b_debug_gradients) { if (b_debug_gradients) {
cvm::log("S = "+cvm::to_str(S_backup, cvm::cv_width, cvm::cv_prec)+"\n"); cvm::matrix2d<cvm::real> S_backup_out(4, 4);
for (size_t i = 0; i < 4; ++i) {
for (size_t j = 0; j < 4; ++j) {
S_backup_out[i][j] = S_backup[i][j];
}
}
cvm::log("S = "+cvm::to_str(S_backup_out, cvm::cv_width, cvm::cv_prec)+"\n");
} }
S_eigval.resize(4);
S_eigvec.resize(4, 4);
#ifdef COLVARS_LAMMPS #ifdef COLVARS_LAMMPS
MathEigen::Jacobi<cvm::real, MathEigen::Jacobi<cvm::real,
cvm::vector1d<cvm::real> &, cvm::real[4],
cvm::matrix2d<cvm::real> &> *ecalc = cvm::real[4][4]> *ecalc =
reinterpret_cast<MathEigen::Jacobi<cvm::real, reinterpret_cast<MathEigen::Jacobi<cvm::real,
cvm::vector1d<cvm::real> &, cvm::real[4],
cvm::matrix2d<cvm::real> &> *>(jacobi); cvm::real[4][4]> *>(jacobi);
int ierror = ecalc->Diagonalize(S, S_eigval, S_eigvec); int ierror = ecalc->Diagonalize(S, S_eigval, S_eigvec);
if (ierror) { if (ierror) {
@ -404,22 +435,9 @@ void colvarmodule::rotation::calc_optimal_rotation(
"rotational alignment (RMSD, rotateReference, etc).\n"); "rotational alignment (RMSD, rotateReference, etc).\n");
} }
#else #else
diagonalize_matrix(S, S_eigval, S_eigvec); NR::diagonalize_matrix(S, S_eigval, S_eigvec);
#endif #endif
q = cvm::quaternion{S_eigvec[0][0], S_eigvec[0][1], S_eigvec[0][2], S_eigvec[0][3]};
// eigenvalues and eigenvectors
cvm::real const L0 = S_eigval[0];
cvm::real const L1 = S_eigval[1];
cvm::real const L2 = S_eigval[2];
cvm::real const L3 = S_eigval[3];
cvm::quaternion const Q0(S_eigvec[0]);
cvm::quaternion const Q1(S_eigvec[1]);
cvm::quaternion const Q2(S_eigvec[2]);
cvm::quaternion const Q3(S_eigvec[3]);
lambda = L0;
q = Q0;
if (cvm::rotation::monitor_crossings) { if (cvm::rotation::monitor_crossings) {
if (q_old.norm2() > 0.0) { if (q_old.norm2() > 0.0) {
@ -431,178 +449,4 @@ void colvarmodule::rotation::calc_optimal_rotation(
} }
q_old = q; q_old = q;
} }
if (b_debug_gradients) {
cvm::log("L0 = "+cvm::to_str(L0, cvm::cv_width, cvm::cv_prec)+
", Q0 = "+cvm::to_str(Q0, cvm::cv_width, cvm::cv_prec)+
", Q0*Q0 = "+cvm::to_str(Q0.inner(Q0), cvm::cv_width, cvm::cv_prec)+
"\n");
cvm::log("L1 = "+cvm::to_str(L1, cvm::cv_width, cvm::cv_prec)+
", Q1 = "+cvm::to_str(Q1, cvm::cv_width, cvm::cv_prec)+
", Q0*Q1 = "+cvm::to_str(Q0.inner(Q1), cvm::cv_width, cvm::cv_prec)+
"\n");
cvm::log("L2 = "+cvm::to_str(L2, cvm::cv_width, cvm::cv_prec)+
", Q2 = "+cvm::to_str(Q2, cvm::cv_width, cvm::cv_prec)+
", Q0*Q2 = "+cvm::to_str(Q0.inner(Q2), cvm::cv_width, cvm::cv_prec)+
"\n");
cvm::log("L3 = "+cvm::to_str(L3, cvm::cv_width, cvm::cv_prec)+
", Q3 = "+cvm::to_str(Q3, cvm::cv_width, cvm::cv_prec)+
", Q0*Q3 = "+cvm::to_str(Q0.inner(Q3), cvm::cv_width, cvm::cv_prec)+
"\n");
}
// calculate derivatives of L0 and Q0 with respect to each atom in
// either group; note: if dS_1 is a null vector, nothing will be
// calculated
size_t ia;
for (ia = 0; ia < dS_1.size(); ia++) {
cvm::real const &a2x = pos2[ia].x;
cvm::real const &a2y = pos2[ia].y;
cvm::real const &a2z = pos2[ia].z;
cvm::matrix2d<cvm::rvector> &ds_1 = dS_1[ia];
// derivative of the S matrix
ds_1.reset();
ds_1[0][0].set( a2x, a2y, a2z);
ds_1[1][0].set( 0.0, a2z, -a2y);
ds_1[0][1] = ds_1[1][0];
ds_1[2][0].set(-a2z, 0.0, a2x);
ds_1[0][2] = ds_1[2][0];
ds_1[3][0].set( a2y, -a2x, 0.0);
ds_1[0][3] = ds_1[3][0];
ds_1[1][1].set( a2x, -a2y, -a2z);
ds_1[2][1].set( a2y, a2x, 0.0);
ds_1[1][2] = ds_1[2][1];
ds_1[3][1].set( a2z, 0.0, a2x);
ds_1[1][3] = ds_1[3][1];
ds_1[2][2].set(-a2x, a2y, -a2z);
ds_1[3][2].set( 0.0, a2z, a2y);
ds_1[2][3] = ds_1[3][2];
ds_1[3][3].set(-a2x, -a2y, a2z);
cvm::rvector &dl0_1 = dL0_1[ia];
cvm::vector1d<cvm::rvector> &dq0_1 = dQ0_1[ia];
// matrix multiplications; derivatives of L_0 and Q_0 are
// calculated using Hellmann-Feynman theorem (i.e. exploiting the
// fact that the eigenvectors Q_i form an orthonormal basis)
dl0_1.reset();
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
dl0_1 += Q0[i] * ds_1[i][j] * Q0[j];
}
}
dq0_1.reset();
for (size_t p = 0; p < 4; p++) {
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
dq0_1[p] +=
(Q1[i] * ds_1[i][j] * Q0[j]) / (L0-L1) * Q1[p] +
(Q2[i] * ds_1[i][j] * Q0[j]) / (L0-L2) * Q2[p] +
(Q3[i] * ds_1[i][j] * Q0[j]) / (L0-L3) * Q3[p];
}
}
}
}
// do the same for the second group
for (ia = 0; ia < dS_2.size(); ia++) {
cvm::real const &a1x = pos1[ia].x;
cvm::real const &a1y = pos1[ia].y;
cvm::real const &a1z = pos1[ia].z;
cvm::matrix2d<cvm::rvector> &ds_2 = dS_2[ia];
ds_2.reset();
ds_2[0][0].set( a1x, a1y, a1z);
ds_2[1][0].set( 0.0, -a1z, a1y);
ds_2[0][1] = ds_2[1][0];
ds_2[2][0].set( a1z, 0.0, -a1x);
ds_2[0][2] = ds_2[2][0];
ds_2[3][0].set(-a1y, a1x, 0.0);
ds_2[0][3] = ds_2[3][0];
ds_2[1][1].set( a1x, -a1y, -a1z);
ds_2[2][1].set( a1y, a1x, 0.0);
ds_2[1][2] = ds_2[2][1];
ds_2[3][1].set( a1z, 0.0, a1x);
ds_2[1][3] = ds_2[3][1];
ds_2[2][2].set(-a1x, a1y, -a1z);
ds_2[3][2].set( 0.0, a1z, a1y);
ds_2[2][3] = ds_2[3][2];
ds_2[3][3].set(-a1x, -a1y, a1z);
cvm::rvector &dl0_2 = dL0_2[ia];
cvm::vector1d<cvm::rvector> &dq0_2 = dQ0_2[ia];
dl0_2.reset();
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
dl0_2 += Q0[i] * ds_2[i][j] * Q0[j];
}
}
dq0_2.reset();
for (size_t p = 0; p < 4; p++) {
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
dq0_2[p] +=
(Q1[i] * ds_2[i][j] * Q0[j]) / (L0-L1) * Q1[p] +
(Q2[i] * ds_2[i][j] * Q0[j]) / (L0-L2) * Q2[p] +
(Q3[i] * ds_2[i][j] * Q0[j]) / (L0-L3) * Q3[p];
}
}
}
if (b_debug_gradients) {
cvm::matrix2d<cvm::real> S_new(4, 4);
cvm::vector1d<cvm::real> S_new_eigval(4);
cvm::matrix2d<cvm::real> S_new_eigvec(4, 4);
// make an infitesimal move along each cartesian coordinate of
// this atom, and solve again the eigenvector problem
for (size_t comp = 0; comp < 3; comp++) {
S_new = S_backup;
// diagonalize the new overlap matrix
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
S_new[i][j] +=
colvarmodule::debug_gradients_step_size * ds_2[i][j][comp];
}
}
// cvm::log("S_new = "+cvm::to_str(cvm::to_str (S_new), cvm::cv_width, cvm::cv_prec)+"\n");
#ifdef COLVARS_LAMMPS
ecalc->Diagonalize(S_new, S_new_eigval, S_new_eigvec);
#else
diagonalize_matrix(S_new, S_new_eigval, S_new_eigvec);
#endif
cvm::real const &L0_new = S_new_eigval[0];
cvm::quaternion const Q0_new(S_new_eigvec[0]);
cvm::real const DL0 = (dl0_2[comp]) * colvarmodule::debug_gradients_step_size;
cvm::quaternion const DQ0(dq0_2[0][comp] * colvarmodule::debug_gradients_step_size,
dq0_2[1][comp] * colvarmodule::debug_gradients_step_size,
dq0_2[2][comp] * colvarmodule::debug_gradients_step_size,
dq0_2[3][comp] * colvarmodule::debug_gradients_step_size);
cvm::log( "|(l_0+dl_0) - l_0^new|/l_0 = "+
cvm::to_str(cvm::fabs(L0+DL0 - L0_new)/L0, cvm::cv_width, cvm::cv_prec)+
", |(q_0+dq_0) - q_0^new| = "+
cvm::to_str((Q0+DQ0 - Q0_new).norm(), cvm::cv_width, cvm::cv_prec)+
"\n");
}
}
}
} }

View File

@ -10,8 +10,14 @@
#ifndef COLVARTYPES_H #ifndef COLVARTYPES_H
#define COLVARTYPES_H #define COLVARTYPES_H
#include <sstream> // TODO specialize templates and replace this with iosfwd
#include <vector> #include <vector>
#ifdef COLVARS_LAMMPS
// Use open-source Jacobi implementation
#include "math_eigen_impl.h"
#endif
#include "colvarmodule.h" #include "colvarmodule.h"
#ifndef PI #ifndef PI
@ -53,6 +59,12 @@ public:
} }
} }
/// Explicit Copy constructor
inline vector1d(const vector1d&) = default;
/// Explicit Copy assignement
inline vector1d& operator=(const vector1d&) = default;
/// Return a pointer to the data location /// Return a pointer to the data location
inline T * c_array() inline T * c_array()
{ {
@ -69,6 +81,12 @@ public:
return data; return data;
} }
/// Return a reference to the data
inline std::vector<T> const &data_array() const
{
return data;
}
inline ~vector1d() inline ~vector1d()
{ {
data.clear(); data.clear();
@ -493,6 +511,12 @@ public:
return data; return data;
} }
/// Return a reference to the data
inline std::vector<T> const &data_array() const
{
return data;
}
inline row & operator [] (size_t const i) inline row & operator [] (size_t const i)
{ {
return rows[i]; return rows[i];
@ -896,9 +920,6 @@ public:
zz = zzi; zz = zzi;
} }
/// Destructor
inline ~rmatrix()
{}
inline void reset() inline void reset()
{ {
@ -1278,59 +1299,50 @@ public:
}; };
#ifndef COLVARS_LAMMPS
namespace NR {
void diagonalize_matrix(cvm::real m[4][4],
cvm::real eigval[4],
cvm::real eigvec[4][4]);
}
#endif
/// \brief A rotation between two sets of coordinates (for the moment /// \brief A rotation between two sets of coordinates (for the moment
/// a wrapper for colvarmodule::quaternion) /// a wrapper for colvarmodule::quaternion)
class colvarmodule::rotation class colvarmodule::rotation
{ {
public: private:
/// \brief The rotation itself (implemented as a quaternion)
cvm::quaternion q;
/// \brief Eigenvalue corresponding to the optimal rotation
cvm::real lambda;
/// \brief Perform gradient tests
bool b_debug_gradients;
/// Correlation matrix C (3, 3) /// Correlation matrix C (3, 3)
cvm::rmatrix C; cvm::rmatrix C;
/// Overlap matrix S (4, 4) /// Overlap matrix S (4, 4)
cvm::matrix2d<cvm::real> S; cvm::real S[4][4];
/// Eigenvalues of S /// Eigenvalues of S
cvm::vector1d<cvm::real> S_eigval; cvm::real S_eigval[4];
/// Eigenvectors of S /// Eigenvectors of S
cvm::matrix2d<cvm::real> S_eigvec; cvm::real S_eigvec[4][4];
/// Used for debugging gradients /// Used for debugging gradients
cvm::matrix2d<cvm::real> S_backup; cvm::real S_backup[4][4];
/// Derivatives of S public:
std::vector< cvm::matrix2d<cvm::rvector> > dS_1, dS_2; /// \brief Perform gradient tests
/// Derivatives of leading eigenvalue bool b_debug_gradients;
std::vector< cvm::rvector > dL0_1, dL0_2;
/// Derivatives of leading eigenvector
std::vector< cvm::vector1d<cvm::rvector> > dQ0_1, dQ0_2;
/// Allocate space for the derivatives of the rotation /// \brief The rotation itself (implemented as a quaternion)
inline void request_group1_gradients(size_t n) cvm::quaternion q;
{
dS_1.resize(n, cvm::matrix2d<cvm::rvector>(4, 4));
dL0_1.resize(n, cvm::rvector(0.0, 0.0, 0.0));
dQ0_1.resize(n, cvm::vector1d<cvm::rvector>(4));
}
/// Allocate space for the derivatives of the rotation template <typename T1, typename T2>
inline void request_group2_gradients(size_t n) friend struct rotation_derivative;
{
dS_2.resize(n, cvm::matrix2d<cvm::rvector>(4, 4)); template<typename T1, typename T2>
dL0_2.resize(n, cvm::rvector(0.0, 0.0, 0.0)); friend void debug_gradients(
dQ0_2.resize(n, cvm::vector1d<cvm::rvector>(4)); cvm::rotation &rot,
} const std::vector<T1> &pos1,
const std::vector<T2> &pos2);
/// \brief Calculate the optimal rotation and store the /// \brief Calculate the optimal rotation and store the
/// corresponding eigenvalue and eigenvector in the arguments l0 and /// corresponding eigenvalue and eigenvector in the arguments l0 and
@ -1344,6 +1356,8 @@ public:
/// DOI: 10.1002/jcc.20110 PubMed: 15376254 /// DOI: 10.1002/jcc.20110 PubMed: 15376254
void calc_optimal_rotation(std::vector<atom_pos> const &pos1, void calc_optimal_rotation(std::vector<atom_pos> const &pos1,
std::vector<atom_pos> const &pos2); std::vector<atom_pos> const &pos2);
void calc_optimal_rotation(std::vector<cvm::atom> const &pos1,
std::vector<atom_pos> const &pos2);
/// Initialize member data /// Initialize member data
int init(); int init();
@ -1478,6 +1492,11 @@ protected:
/// Build the correlation matrix C (used by calc_optimal_rotation()) /// Build the correlation matrix C (used by calc_optimal_rotation())
void build_correlation_matrix(std::vector<cvm::atom_pos> const &pos1, void build_correlation_matrix(std::vector<cvm::atom_pos> const &pos1,
std::vector<cvm::atom_pos> const &pos2); std::vector<cvm::atom_pos> const &pos2);
void build_correlation_matrix(std::vector<cvm::atom> const &pos1,
std::vector<cvm::atom_pos> const &pos2);
/// \brief Actual implementation of `calc_optimal_rotation` (and called by it)
void calc_optimal_rotation_impl();
/// Compute the overlap matrix S (used by calc_optimal_rotation()) /// Compute the overlap matrix S (used by calc_optimal_rotation())
void compute_overlap_matrix(); void compute_overlap_matrix();

View File

@ -8,11 +8,10 @@
// Colvars repository at GitHub. // Colvars repository at GitHub.
#include <vector> #include <vector>
#include <sstream>
#include <iostream>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarvalue.h" #include "colvarvalue.h"
#include "colvars_memstream.h"
@ -721,29 +720,43 @@ int colvarvalue::from_simple_string(std::string const &s)
return COLVARS_ERROR; return COLVARS_ERROR;
} }
std::ostream & operator << (std::ostream &os, colvarvalue const &x)
template <typename OST> void colvarvalue::write_to_stream_template_(OST &os) const
{ {
switch (x.type()) { switch (type()) {
case colvarvalue::type_scalar: case colvarvalue::type_scalar:
os << x.real_value; os << real_value;
break; break;
case colvarvalue::type_3vector: case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector: case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv: case colvarvalue::type_unit3vectorderiv:
os << x.rvector_value; os << rvector_value;
break; break;
case colvarvalue::type_quaternion: case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv: case colvarvalue::type_quaternionderiv:
os << x.quaternion_value; os << quaternion_value;
break; break;
case colvarvalue::type_vector: case colvarvalue::type_vector:
os << x.vector1d_value; os << vector1d_value;
break; break;
case colvarvalue::type_notset: case colvarvalue::type_notset:
default: default:
os << "not set"; os << "not set";
break; break;
} }
}
std::ostream & operator << (std::ostream &os, colvarvalue const &x)
{
x.write_to_stream_template_<std::ostream>(os);
return os;
}
cvm::memory_stream & operator << (cvm::memory_stream &os, colvarvalue const &x)
{
x.write_to_stream_template_<cvm::memory_stream>(os);
return os; return os;
} }
@ -758,44 +771,55 @@ std::ostream & operator << (std::ostream &os, std::vector<colvarvalue> const &v)
} }
std::istream & operator >> (std::istream &is, colvarvalue &x) template <typename IST> void colvarvalue::read_from_stream_template_(IST &is)
{ {
if (x.type() == colvarvalue::type_notset) { if (type() == colvarvalue::type_notset) {
cvm::error("Trying to read from a stream a colvarvalue, " cvm::error("Trying to read from a stream a colvarvalue, "
"which has not yet been assigned a data type.\n"); "which has not yet been assigned a data type.\n");
return is;
} }
switch (x.type()) { switch (type()) {
case colvarvalue::type_scalar: case colvarvalue::type_scalar:
is >> x.real_value; is >> real_value;
break; break;
case colvarvalue::type_3vector: case colvarvalue::type_3vector:
case colvarvalue::type_unit3vectorderiv: case colvarvalue::type_unit3vectorderiv:
is >> x.rvector_value; is >> rvector_value;
break; break;
case colvarvalue::type_unit3vector: case colvarvalue::type_unit3vector:
is >> x.rvector_value; is >> rvector_value;
x.apply_constraints(); apply_constraints();
break; break;
case colvarvalue::type_quaternion: case colvarvalue::type_quaternion:
is >> x.quaternion_value; is >> quaternion_value;
x.apply_constraints(); apply_constraints();
break; break;
case colvarvalue::type_quaternionderiv: case colvarvalue::type_quaternionderiv:
is >> x.quaternion_value; is >> quaternion_value;
break; break;
case colvarvalue::type_vector: case colvarvalue::type_vector:
is >> x.vector1d_value; is >> vector1d_value;
break; break;
case colvarvalue::type_notset: case colvarvalue::type_notset:
default: default:
x.undef_op(); undef_op();
} }
}
std::istream & operator >> (std::istream &is, colvarvalue &x)
{
x.read_from_stream_template_<std::istream>(is);
return is; return is;
} }
cvm::memory_stream & operator >> (cvm::memory_stream &is, colvarvalue &x)
{
x.read_from_stream_template_<cvm::memory_stream>(is);
return is;
}
size_t colvarvalue::output_width(size_t const &real_width) const size_t colvarvalue::output_width(size_t const &real_width) const
{ {
switch (this->value_type) { switch (this->value_type) {

View File

@ -10,6 +10,8 @@
#ifndef COLVARVALUE_H #ifndef COLVARVALUE_H
#define COLVARVALUE_H #define COLVARVALUE_H
#include <list>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvartypes.h" #include "colvartypes.h"
@ -120,7 +122,8 @@ public:
/// number and always behaves like it unless you change its type /// number and always behaves like it unless you change its type
colvarvalue(); colvarvalue();
/// Constructor from a type specification /// Constructor from a type flag (note: type_vector also needs the vector length to be set)
/// \param[in] vti Value of the \link Type \endlink enum
colvarvalue(Type const &vti); colvarvalue(Type const &vti);
/// Copy constructor from real base type /// Copy constructor from real base type
@ -297,12 +300,31 @@ public:
/// Undefined operation /// Undefined operation
void undef_op() const; void undef_op() const;
private:
/// \brief Formatted output operator /// Generic stream writing function (formatted and not)
friend std::ostream & operator << (std::ostream &os, colvarvalue const &q); template <typename OST> void write_to_stream_template_(OST &os) const;
/// \brief Formatted input operator public:
friend std::istream & operator >> (std::istream &is, colvarvalue &q);
/// Formatted output operator
friend std::ostream & operator << (std::ostream &os, colvarvalue const &x);
/// Unformatted output operator
friend cvm::memory_stream & operator << (cvm::memory_stream &os, colvarvalue const &x);
private:
/// Generic stream reading function (formatted and not)
template <typename IST> void read_from_stream_template_(IST &is);
public:
/// Formatted input operator
friend std::istream & operator >> (std::istream &is, colvarvalue &x);
/// Unformatted input operator
friend cvm::memory_stream & operator >> (cvm::memory_stream &is, colvarvalue &x);
/// Give the number of characters required to output this /// Give the number of characters required to output this
/// colvarvalue, given the current type assigned and the number of /// colvarvalue, given the current type assigned and the number of