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 = \
colvaratoms.cpp \
colvarbias_abf.cpp \
colvarbias_abmd.cpp \
colvarbias_alb.cpp \
colvarbias.cpp \
colvarbias_histogram.cpp \
@ -59,6 +60,7 @@ COLVARS_SRCS = \
colvarscript_commands.cpp \
colvarscript_commands_bias.cpp \
colvarscript_commands_colvar.cpp \
colvars_memstream.cpp \
colvartypes.cpp \
colvarvalue.cpp \
colvar_neuralnetworkcompute.cpp

View File

@ -1,201 +1,230 @@
$(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \
$(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvardeps.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_volmaps.h colvarparse.h colvarparams.h colvaratoms.h \
colvardeps.h
colvarproxy_volmaps.h colvaratoms.h colvar_rotation_derivative.h
$(COLVARS_OBJ_DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h \
colvars_version.h colvar.h colvarvalue.h colvartypes.h colvarparse.h \
colvarparams.h colvardeps.h colvarbias_abf.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvarbias.h colvargrid.h colvar_UIestimator.h
colvars_version.h colvar.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarbias_abf.h colvarproxy.h colvarproxy_io.h colvarproxy_system.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_version.h colvarbias.h colvar.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h colvarbias_alb.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 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_version.h colvarproxy.h colvartypes.h colvarvalue.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvarbias.h colvar.h colvarparse.h colvarparams.h \
colvardeps.h colvargrid.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 colvarvalue.h colvarbias.h \
colvar.h colvarparse.h colvarparams.h colvardeps.h colvargrid.h \
colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \
colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar.h colvarparse.h colvarparams.h colvardeps.h \
colvarbias_histogram.h colvarbias.h colvargrid.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_histogram.h \
colvarbias.h colvargrid.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_histogram_reweight_amd.o: \
colvarbias_histogram_reweight_amd.cpp \
colvarbias_histogram_reweight_amd.h colvarbias_histogram.h colvarbias.h \
colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h colvargrid.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h
../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvargrid.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar.h colvarparse.h colvarparams.h colvardeps.h \
colvarbias_meta.h colvarbias.h colvargrid.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_meta.h colvarbias.h \
colvargrid.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \
colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvarbias_restraint.h colvarbias.h colvar.h \
colvarparse.h colvarparams.h colvardeps.h
../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvarvalue.h \
colvarbias_restraint.h colvarbias.h colvar.h colvarparse.h \
colvarparams.h colvardeps.h
$(COLVARS_OBJ_DIR)colvarcomp_alchlambda.o: colvarcomp_alchlambda.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 \
../../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_angles.o: colvarcomp_angles.cpp \
colvarmodule.h colvars_version.h colvar.h colvarvalue.h colvartypes.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_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 \
../../src/math_eigen_impl.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_gpath.o: colvarcomp_gpath.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_neuralnetwork.o: \
colvarcomp_neuralnetwork.cpp colvarmodule.h colvars_version.h \
colvarvalue.h colvartypes.h colvarparse.h colvarparams.h colvar.h \
$(COLVARS_OBJ_DIR)colvarcomp_apath.o: colvarcomp_apath.cpp colvarvalue.h \
colvarmodule.h colvars_version.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_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
$(COLVARS_OBJ_DIR)colvarcomp_combination.o: colvarcomp_combination.cpp \
colvarcomp.h colvarmodule.h colvars_version.h colvar.h colvarvalue.h \
colvartypes.h colvarparse.h colvarparams.h colvardeps.h colvaratoms.h \
colvarproxy.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h
colvarcomp.h 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 \
colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.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 \
../../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_rotations.o: colvarcomp_rotations.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_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 \
../../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_arithmeticpath.h colvar_geometricpath.h colvarscript.h \
colvarbias.h colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h
colvar_geometricpath.h colvar_rotation_derivative.h
$(COLVARS_OBJ_DIR)colvarcomp_volmaps.o: colvarcomp_volmaps.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)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_version.h colvarproxy.h colvartypes.h colvarvalue.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.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 colvardeps.h colvarparse.h \
colvarvalue.h colvarparams.h
$(COLVARS_OBJ_DIR)colvargrid.o: colvargrid.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 \
colvargrid.h colvargrid_def.h
colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvar.h \
colvardeps.h colvargrid.h colvargrid_def.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvars_memstream.h
$(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \
colvars_version.h colvarparse.h colvarvalue.h colvartypes.h \
colvarparams.h colvarproxy.h colvarproxy_io.h colvarproxy_system.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 \
../../src/math_eigen_impl.h colvarparams.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvarscript.h colvarbias.h colvar.h colvarparse.h \
colvarparams.h colvardeps.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h \
colvaratoms.h colvarmodule_utils.h
colvarproxy_volmaps.h colvar.h colvardeps.h colvarbias.h \
colvarbias_abf.h colvargrid.h colvar_UIestimator.h colvarbias_abmd.h \
colvarbias_restraint.h colvarbias_alb.h colvarbias_histogram.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_version.h colvarproxy_io.h
$(COLVARS_OBJ_DIR)colvarproxy_replicas.o: colvarproxy_replicas.cpp \
colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h
../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h
$(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_version.h colvarproxy.h colvartypes.h colvarvalue.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvaratoms.h colvarparse.h colvarparams.h \
colvardeps.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 colvaratoms.h colvarparse.h \
colvarvalue.h colvarparams.h colvardeps.h
$(COLVARS_OBJ_DIR)colvarproxy_volmaps.o: colvarproxy_volmaps.cpp \
colvarmodule.h colvars_version.h colvarproxy_volmaps.h \
colvarmodule_utils.h
$(COLVARS_OBJ_DIR)colvarscript.o: colvarscript.cpp colvarproxy.h \
colvarmodule.h colvars_version.h colvartypes.h colvarvalue.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h \
colvarscript.h colvarbias.h colvar.h colvarscript_commands.h \
colvarmodule.h colvars_version.h colvartypes.h \
../../src/math_eigen_impl.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h colvarparse.h \
colvarvalue.h colvarparams.h colvarscript.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvarscript_commands.o: colvarscript_commands.cpp \
colvarproxy.h colvarmodule.h colvars_version.h colvartypes.h \
colvarvalue.h colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h \
colvarscript.h colvarbias.h colvar.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h
colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
../../src/math_eigen_impl.h colvarparse.h colvarparams.h colvardeps.h \
colvarbias.h colvarproxy.h colvarproxy_io.h colvarproxy_system.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvarscript.h \
colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvarscript_commands_bias.o: \
colvarscript_commands_bias.cpp colvarproxy.h colvarmodule.h \
colvars_version.h colvartypes.h colvarvalue.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvardeps.h colvarparse.h colvarparams.h colvarscript.h colvarbias.h \
colvar.h colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h
colvars_version.h colvartypes.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 colvarscript.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvarscript_commands_colvar.o: \
colvarscript_commands_colvar.cpp colvarproxy.h colvarmodule.h \
colvars_version.h colvartypes.h colvarvalue.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvardeps.h colvarparse.h colvarparams.h colvarscript.h colvarbias.h \
colvar.h colvarscript_commands.h colvarscript_commands_colvar.h \
colvarscript_commands_bias.h
colvarscript_commands_colvar.cpp 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 colvarscript.h colvarscript_commands.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_version.h colvartypes.h colvarparse.h colvarvalue.h \
colvarparams.h ../../src/math_eigen_impl.h
colvars_version.h colvartypes.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_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: \
colvar_neuralnetworkcompute.cpp colvar_neuralnetworkcompute.h \
colvarparse.h colvarmodule.h colvars_version.h colvarvalue.h \
colvartypes.h colvarparams.h colvarproxy.h colvarproxy_io.h \
colvarproxy_system.h colvarproxy_tcl.h colvarproxy_volmaps.h
colvartypes.h ../../src/math_eigen_impl.h colvarparams.h colvarproxy.h \
colvarproxy_io.h colvarproxy_system.h colvarproxy_tcl.h \
colvarproxy_volmaps.h

View File

@ -16,13 +16,18 @@
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.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()
{
@ -36,6 +41,8 @@ colvar::colvar()
dev_null = 0.0;
#endif
matching_state = false;
expand_boundaries = false;
description = "uninitialized colvar";
@ -131,7 +138,14 @@ int colvar::init(std::string const &conf)
// Sort array of cvcs based on their names
// 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) {
cvm::log("Sorted list of components for this scripted colvar:\n");
@ -188,7 +202,7 @@ int colvar::init(std::string const &conf)
cvm::log("Warning: you chose a negative exponent in the combination; "
"if you apply forces, the simulation may become unstable "
"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);
// 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);
}
@ -468,13 +482,6 @@ int colvar::init_custom_function(std::string const &conf)
size_t pos = 0;
if (key_lookup(conf, "customFunction", &expr, &pos)) {
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);
}
@ -697,9 +704,14 @@ int colvar::init_extended_Lagrangian(std::string const &conf)
}
if (ext_gamma != 0.0) {
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
// 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);
@ -744,75 +756,56 @@ int colvar::init_output_flags(std::string const &conf)
return COLVARS_OK;
}
#if (__cplusplus >= 201103L)
// C++11
template<typename def_class_name> int colvar::init_components_type(std::string const &,
char const * /* def_desc */,
char const *def_config_key) {
// global_cvc_map is only supported in the C++11 case
global_cvc_map[def_config_key] = [](const std::string& cvc_conf){return new def_class_name(cvc_conf);};
// TODO: maybe it is better to do more check to avoid duplication in the map?
return COLVARS_OK;
template <typename def_class_name>
void colvar::add_component_type(char const *def_description, char const *def_config_key)
{
if (global_cvc_map.count(def_config_key) == 0) {
global_cvc_map[def_config_key] = []() {
return new def_class_name();
};
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) {
#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
int colvar::init_components_type(const std::string& conf, const char* def_config_key) {
size_t def_count = 0;
std::string def_conf = "";
size_t pos = 0;
int error_code = COLVARS_OK;
while ( this->key_lookup(conf,
def_config_key,
&def_conf,
&pos) ) {
if (!def_conf.size()) continue;
cvm::log("Initializing "
"a new \""+std::string(def_config_key)+"\" component"+
(cvm::debug() ? ", with configuration:\n"+def_conf
: ".\n"));
cvm::increase_depth();
// only the following line is different from init_components_type
// in the non-C++11 case
#if (__cplusplus >= 201103L)
cvc *cvcp = global_cvc_map.at(def_config_key)(def_conf);
#else
cvc *cvcp = new def_class_name(def_conf);
#endif
if (cvcp != NULL) {
cvcs.push_back(cvcp);
cvcp->check_keywords(def_conf, def_config_key);
cvcp->set_function_type(def_config_key);
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",
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);
return COLVARS_MEMORY_ERROR;
}
cvcs.push_back(std::shared_ptr<colvar::cvc>(cvcp));
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),
cvm::increase_depth();
int error_code_this = cvcp->init(def_conf);
if (error_code_this == COLVARS_OK) {
// Checking for invalid keywords only if the parsing was successful, otherwise any
// early-returns due to errors would raise false positives
error_code_this |= cvcp->check_keywords(def_conf, def_config_key);
}
cvm::decrease_depth();
if (error_code_this != COLVARS_OK) {
error_code |=
cvm::error("Error: in setting up component \"" + std::string(def_config_key) + "\".\n",
COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
}
}
// Set default name if it doesn't have one
if ( ! cvcs.back()->name.size()) {
std::ostringstream s;
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();
if (cvm::debug()) {
cvm::log("Done initializing a \""+
std::string(def_config_key)+
"\" component"+
(cvm::debug() ?
", named \""+cvcs.back()->name+"\""
: "")+".\n");
cvm::log("Done initializing a \"" + std::string(def_config_key) + "\" component" +
(cvm::debug() ? ", named \"" + cvcs.back()->name + "\"" : "") + ".\n");
}
def_conf = "";
if (cvm::debug()) {
cvm::log("Parsed "+cvm::to_str(cvcs.size())+
" components at this time.\n");
cvm::log("Parsed " + cvm::to_str(cvcs.size()) + " 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 error_code = COLVARS_OK;
size_t i = 0, j = 0;
// in the non-C++11 case, the components are initialized directly by init_components_type;
// in the C++11 case, the components are stored in the global_cvc_map at first
// 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");
if (global_cvc_map.empty()) {
define_component_types();
}
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
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?
if (error_code != COLVARS_OK) {
cvm::log("Failed to initialize " + it->first + " with the following configuration:\n");
cvm::log(conf);
// TODO: should it stop here?
break;
}
}
#endif
if (!cvcs.size() || (error_code != COLVARS_OK)) {
cvm::error("Error: no valid components were provided "
"for this collective variable.\n",
COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
if (!cvcs.size()) {
std::string msg("Error: no valid components were provided for this collective variable.\n");
msg += "Currently available component types are: \n";
for (auto it = global_cvc_desc_map.begin(); it != global_cvc_desc_map.end(); ++it) {
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)
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) {
cvm::error("Components " + cvm::to_str(i) + " and " + cvm::to_str(j) +\
" cannot have the same name \"" + cvcs[i]->name+ "\".\n", COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
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);
}
}
}
n_active_cvcs = cvcs.size();
if (error_code == COLVARS_OK) {
// Store list of children cvcs for dependency checking purposes
for (i = 0; i < cvcs.size(); i++) {
add_child(cvcs[i]);
add_child(cvcs[i].get());
}
// 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 COLVARS_OK;
return error_code;
}
@ -1220,7 +1216,7 @@ int colvar::init_dependencies() {
// Initialize feature_states for each instance
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));
// Most features are available, so we set them so
// and list exceptions below
@ -1283,14 +1279,10 @@ colvar::~colvar()
// for dependency purposes
remove_all_children();
for (std::vector<cvc *>::reverse_iterator ci = cvcs.rbegin();
ci != cvcs.rend();
++ci) {
// 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
for (auto ci = cvcs.rbegin(); ci != cvcs.rend(); ++ci) {
// 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();
delete *ci;
}
cvcs.clear();
@ -1512,6 +1504,7 @@ int colvar::collect_cvc_values()
cvm::to_str(x, cvm::cv_width, cvm::cv_prec)+".\n");
if (after_restart) {
x_old = x_restart;
if (cvm::proxy->simulation_running()) {
cvm::real const jump2 = dist2(x, x_restart) / (width*width);
if (jump2 > 0.25) {
@ -1555,12 +1548,12 @@ int colvar::calc_cvc_gradients(int first_cvc, size_t num_cvcs)
(cvcs[i])->debug_gradients();
}
cvm::decrease_depth();
if (cvm::debug())
cvm::log("Done calculating gradients of colvar \""+this->name+"\".\n");
}
cvm::decrease_depth();
return COLVARS_OK;
}
@ -1706,12 +1699,13 @@ int colvar::calc_colvar_properties()
// 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()) {
x_ext = x;
cvm::log("Initializing extended coordinate to colvar value.\n");
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;
}
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;
}
@ -1721,9 +1715,19 @@ int colvar::calc_colvar_properties()
// Special case of a repeated timestep (eg. multiple NAMD "run" statements)
// revert values of the extended coordinate and velocity prior to latest integration
if (cvm::proxy->simulation_running() && cvm::step_relative() == prev_timestep) {
// Detect jumps due to discrete changes in coordinates (eg. in replica exchange schemes)
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"
// These position and velocities come from integration at the _previous timestep_ in update_forces_energy()
// But we report values at the beginning of the timestep (value at t=0 on the first timestep)
@ -1830,9 +1834,11 @@ void colvar::update_extended_Lagrangian()
f += fb_actual;
}
// fr: bias force on extended variable (without harmonic spring), for output in trajectory
fr = f;
// External force has been scaled for a 1-timestep impulse, scale it back because we will
// 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);
colvarvalue f_system(fr.type()); // force exterted by the system on the extended DOF
@ -1845,15 +1851,14 @@ void colvar::update_extended_Lagrangian()
} else {
// the total force is applied to the fictitious mass, while the
// 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: - initially, external biasing force
// - after this code block, colvar force to be applied to atomic coordinates
// ie. spring force (fb_actual will be added just below)
f_system = (-0.5 * ext_force_k) * this->dist2_lgrad(x_ext, x);
f = -1.0 * f_system;
// Coupling force is a slow force, to be applied to atomic coords impulse-style
// over a single MD timestep
// Coupling force will be applied to atomic coords impulse-style
// over an inner timestep of the back-end integrator
f *= cvm::real(time_step_factor);
}
f_ext += f_system;
@ -1873,34 +1878,57 @@ void colvar::update_extended_Lagrangian()
prev_x_ext = x_ext;
prev_v_ext = v_ext;
// leapfrog: starting from x_i, f_i, v_(i-1/2)
v_ext += (0.5 * dt) * f_ext / ext_mass;
// Because of leapfrog, kinetic energy at time i is approximate
// BAOA (GSD) integrator as formulated in https://doi.org/10.1021/acs.jctc.2c00585
// starting from x_t, f_t, v_(t-1/2)
// 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;
// Potential energy at t
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)) {
v_ext -= dt * ext_gamma * v_ext;
colvarvalue rnd(x);
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;
x_ext += dt * v_ext;
// [A] Second half step in position (10d)
x_ext += dt * v_ext / 2.0;
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) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) {
// Reflect arrival position
x_ext -= 2.0 * delta;
v_ext *= -1.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)) {
// Bounce happened on average at t+1/2 -> reflect velocity at t+1/2
v_ext = -0.5 * (prev_v_ext + v_ext);
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");
}
}
x_ext.apply_constraints();
this->wrap(x_ext);
if (is_enabled(f_cv_external)) {
// Colvar value is constrained to the extended value
x = x_ext;
@ -1914,9 +1942,8 @@ int colvar::end_of_step()
if (cvm::debug())
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;
}
if (is_enabled(f_cv_subtract_applied_force)) {
f_old = f;
@ -2256,44 +2283,65 @@ void colvar::wrap(colvarvalue &x_unwrapped) const
std::istream & colvar::read_state(std::istream &is)
{
std::streampos const start_pos = is.tellg();
auto const start_pos = is.tellg();
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
is.clear();
is.seekg(start_pos, std::ios::beg);
is.seekg(start_pos);
is.setstate(std::ios::failbit);
return is;
}
{
std::string check_name = "";
get_keyval(conf, "name", check_name,
std::string(""), colvarparse::parse_silent);
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);
if (!matching_state) {
// No errors reading, but this state is not for this colvar; rewind
is.seekg(start_pos);
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");
}
is.seekg(start_pos, std::ios::beg);
return is;
}
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)) ) {
cvm::log("Error: restart file does not contain "
error_code |= cvm::error("Error: restart file does not contain "
"the value of the colvar \""+
name+"\" .\n");
name+"\" .\n", COLVARS_INPUT_ERROR);
} else {
cvm::log("Restarting collective variable \""+name+"\" from value: "+
cvm::to_str(x)+"\n");
@ -2306,9 +2354,10 @@ std::istream & colvar::read_state(std::istream &is)
colvarvalue(x.type()), colvarparse::parse_silent)) ||
!(get_keyval(conf, "extended_v", v_ext,
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 \""+
name+"\", but you requested \"extendedLagrangian\".\n");
name+"\", but you requested \"extendedLagrangian\".\n",
COLVARS_INPUT_ERROR);
}
x_reported = x_ext;
} else {
@ -2319,9 +2368,10 @@ std::istream & colvar::read_state(std::istream &is)
if ( !(get_keyval(conf, "v", v_fdiff,
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 \""+
name+"\", but you requested \"outputVelocity\".\n");
name+"\", but you requested \"outputVelocity\".\n",
COLVARS_INPUT_ERROR);
}
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;
}
@ -2345,7 +2430,7 @@ std::istream & colvar::read_traj(std::istream &is)
cvm::log("Error: in reading the value of colvar \""+
this->name+"\" from trajectory.\n");
is.clear();
is.seekg(start_pos, std::ios::beg);
is.seekg(start_pos);
is.setstate(std::ios::failbit);
return is;
}
@ -2385,10 +2470,23 @@ std::istream & colvar::read_traj(std::istream &is)
// ******************** 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"
<< " name " << name << "\n"
if (runave_outfile.size() > 0) {
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 "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
@ -2412,7 +2510,13 @@ std::ostream & colvar::write_state(std::ostream &os) {
<< 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) {
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);
if (runave_outfile.size() > 0) {
std::ostream &runave_os = proxy->output_stream(runave_outfile);
runave_os << std::setw(cvm::it_width) << cvm::step_relative()
<< " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< runave << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
std::ostream &runave_os =
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::setw(cvm::cv_width) << runave << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< cvm::sqrt(runave_variance) << "\n";
}
}

View File

@ -10,12 +10,11 @@
#ifndef COLVAR_H
#define COLVAR_H
#include <iostream>
#if (__cplusplus >= 201103L)
#include <map>
#include <functional>
#endif
#include <list>
#include <iosfwd>
#include <map>
#include <memory>
#include "colvarmodule.h"
#include "colvarvalue.h"
@ -91,7 +90,7 @@ public:
/// calculations, \link colvarbias_abf \endlink, it is used to
/// calculate the grid spacing in the direction of this collective
/// variable.
cvm::real width;
cvm::real width = 1.0;
/// \brief Implementation of the feature list for colvar
static std::vector<feature *> cv_features;
@ -184,13 +183,13 @@ protected:
/// Previous velocity of the restraint center
colvarvalue prev_v_ext;
/// Mass of the restraint center
cvm::real ext_mass;
cvm::real ext_mass = 0.0;
/// Restraint force constant
cvm::real ext_force_k;
cvm::real ext_force_k = 0.0;
/// 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
cvm::real ext_sigma;
cvm::real ext_sigma = 0.0;
/// \brief Applied force on extended DOF, for output (unscaled if using MTS)
colvarvalue fr;
@ -224,14 +223,14 @@ public:
colvarvalue ft;
/// Period, if this variable is periodic
cvm::real period;
cvm::real period = 0.0;
/// 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
/// value always within range
bool expand_boundaries;
bool expand_boundaries = false;
/// \brief Location of the lower boundary
colvarvalue lower_boundary;
@ -252,6 +251,9 @@ public:
/// Main init function
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
int init_components(std::string const &conf);
@ -271,17 +273,13 @@ public:
virtual int init_dependencies();
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,
char const *def_desc,
char const *def_config_key);
#if (__cplusplus >= 201103L)
/// For the C++11 case, the names of all available components are
/// registered in the global map at first, and then the CVC configuration
/// is parsed by this function
int init_components_type_from_global_map(const std::string& conf,
const char* def_config_key);
#endif
/// Declare an available CVC type and its description, register them in the global map
template <typename def_class_name>
void add_component_type(char const *description, char const *config_key);
/// Initialize any CVC objects matching the given key
int init_components_type(const std::string &conf, const char *config_key);
public:
@ -387,10 +385,10 @@ public:
protected:
/// \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
cvm::real active_cvc_square_norm;
cvm::real active_cvc_square_norm = 0.0;
/// Update the sum of square coefficients for active cvcs
void update_active_cvc_square_norm();
@ -460,16 +458,35 @@ public:
/// Write a label to the trajectory file (comment line)
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);
/// 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)
int write_output_files();
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)
colvarvalue x_old;
@ -554,15 +571,15 @@ protected:
/// Current value of the running average
colvarvalue runave;
/// 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
int calc_runave();
/// If extended Lagrangian active: colvar kinetic energy
cvm::real kinetic_energy;
cvm::real kinetic_energy = 0.0;
/// If extended Lagrangian active: colvar harmonic potential
cvm::real potential_energy;
cvm::real potential_energy = 0.0;
public:
@ -601,8 +618,9 @@ public:
class dihedPC;
class alch_lambda;
class alch_Flambda;
class componentDisabled;
class CartesianBasedPath;
class aspath;
class azpath;
class gspath;
class gzpath;
class linearCombination;
@ -626,21 +644,19 @@ public:
// components that do not handle any atoms directly
class map_total;
/// getter of the global cvc map
#if (__cplusplus >= 201103L)
/// 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;
}
#endif
/// \brief function for sorting cvcs by their names
static bool compare_cvc(const colvar::cvc* const i, const colvar::cvc* const j);
protected:
/// \brief Array of \link colvar::cvc \endlink objects
std::vector<cvc *> cvcs;
/// Array of components objects
std::vector<std::shared_ptr<colvar::cvc>> cvcs;
/// \brief Flags to enable or disable cvcs at next colvar evaluation
std::vector<bool> cvc_flags;
@ -671,10 +687,11 @@ protected:
double dev_null;
#endif
#if (__cplusplus >= 201103L)
/// 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;
#endif
static std::map<std::string, std::function<colvar::cvc *()>> global_cvc_map;
/// 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)
std::vector<int> volmap_ids_;
@ -762,4 +779,3 @@ inline void colvar::reset_bias_force() {
}
#endif

View File

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

View File

@ -8,12 +8,13 @@
// Colvars repository at GitHub.
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include "colvarmodule.h"
#include <vector>
#include <cmath>
#include <algorithm>
#include <string>
namespace GeometricPathCV {
@ -171,10 +172,14 @@ void GeometricPathBase<element_type, scalar_type, path_type>::determineClosestFr
sign = -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::cout << " Please check your configuration or increase restraint on z(σ)\n";
std::string message(
"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) {
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

View File

@ -10,7 +10,6 @@
#include <iostream>
#include <fstream>
#if (__cplusplus >= 201103L)
#include "colvar_neuralnetworkcompute.h"
#include "colvarparse.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();
std::vector<std::vector<double>> C(m, std::vector<double>(t, 0.0));
for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < t; ++j) {
for (size_t k = 0; k < n; ++k) {
C[i][j] += A[i][k] * B[k][j];
const auto tmp = A[i][k];
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
// Colvars repository at GitHub.
#if (__cplusplus >= 201103L)
#ifndef NEURALNETWORKCOMPUTE_H
#define NEURALNETWORKCOMPUTE_H
@ -145,4 +144,3 @@ public:
}
#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 <iomanip>
#include "colvardeps.h"
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvarparse.h"
#include "colvaratoms.h"
#include "colvar_rotation_derivative.h"
cvm::atom::atom()
@ -118,6 +120,11 @@ cvm::atom_group::~atom_group()
fitting_group = NULL;
}
if (rot_deriv != nullptr) {
delete rot_deriv;
rot_deriv = nullptr;
}
cvm::main()->unregister_named_atom_group(this);
}
@ -226,6 +233,7 @@ int cvm::atom_group::init()
b_dummy = false;
b_user_defined_fit = false;
fitting_group = NULL;
rot_deriv = nullptr;
noforce = false;
@ -278,7 +286,7 @@ int cvm::atom_group::init_dependencies() {
// Initialize feature_states for each instance
// default as unavailable, not enabled
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));
}
@ -317,6 +325,13 @@ int cvm::atom_group::setup()
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()
{
@ -383,7 +398,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
// }
// 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
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");
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 = "";
size_t pos = 0;
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 = "";
}
}
@ -456,7 +471,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
std::string index_group_name;
if (get_keyval(group_conf, "indexGroup", index_group_name)) {
// 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;
while (key_lookup(group_conf, "atomNumbersRange",
&range_conf, &pos)) {
parse_error |= add_atom_numbers_range(range_conf);
error_code |= add_atom_numbers_range(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 "
"values of \"psfSegID\".\n", COLVARS_INPUT_ERROR);
} 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);
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);
}
// NOTE: calls to add_atom() and/or add_atom_id() are in the proxy-implemented function
parse_error |= cvm::load_atoms(atoms_file_name.c_str(), *this, atoms_col, atoms_col_value);
error_code |= cvm::main()->proxy->load_atoms_pdb(atoms_file_name.c_str(), *this, atoms_col,
atoms_col_value);
}
}
// 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
if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos())) {
parse_error |= set_dummy();
parse_error |= set_dummy_pos(dummy_atom_pos);
error_code |= set_dummy();
error_code |= set_dummy_pos(dummy_atom_pos);
} else {
if (!(atoms_ids.size())) {
parse_error |= cvm::error("Error: no atoms defined for atom group \""+
key+"\".\n", COLVARS_INPUT_ERROR);
error_code |= cvm::error("Error: no atoms defined for atom group \"" + key + "\".\n",
COLVARS_INPUT_ERROR);
}
// 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
parse_error |= parse_fitting_options(group_conf);
error_code |= parse_fitting_options(group_conf);
if (is_enabled(f_ag_scalable) && !b_dummy) {
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());
}
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. "
"If that happens, use fittingGroup (or a different definition for it if already defined) "
"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)) {
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));
rot.request_group1_gradients(group_for_fit->size());
}
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
// enabled, around the origin otherwise)
rot.calc_optimal_rotation(fitting_group ?
fitting_group->positions() :
this->positions(),
fitting_group->atoms:
this->atoms,
ref_pos);
const auto rot_mat = rot.matrix();
cvm::atom_iter ai;
for (ai = this->begin(); ai != this->end(); ai++) {
ai->pos = rot.rotate(ai->pos);
ai->pos = rot_mat * ai->pos;
}
if (fitting_group) {
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)) {
const auto rot_mat = rot.matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_velocity();
ai->vel = rot.rotate(ai->vel);
ai->vel = rot_mat * ai->vel;
}
} else {
@ -1116,9 +1132,10 @@ void cvm::atom_group::read_total_forces()
if (is_enabled(f_ag_rotate)) {
const auto rot_mat = rot.matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_total_force();
ai->total_force = rot.rotate(ai->total_force);
ai->total_force = rot_mat * ai->total_force;
}
} else {
@ -1200,52 +1217,71 @@ void cvm::atom_group::calc_fit_gradients()
if (cvm::debug())
cvm::log("Calculating fit gradients.\n");
cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this;
if (is_enabled(f_ag_center)) {
// add the center of geometry contribution to the gradients
cvm::rvector atom_grad;
for (size_t i = 0; i < this->size(); i++) {
atom_grad += atoms[i].grad;
}
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 (is_enabled(f_ag_center) && is_enabled(f_ag_rotate))
calc_fit_gradients_impl<true, true>();
if (is_enabled(f_ag_center) && !is_enabled(f_ag_rotate))
calc_fit_gradients_impl<true, false>();
if (!is_enabled(f_ag_center) && is_enabled(f_ag_rotate))
calc_fit_gradients_impl<false, true>();
if (!is_enabled(f_ag_center) && !is_enabled(f_ag_rotate))
calc_fit_gradients_impl<false, false>();
if (cvm::debug())
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
{
if (b_dummy) {
@ -1373,9 +1409,9 @@ void cvm::atom_group::apply_colvar_force(cvm::real const &force)
if (is_enabled(f_ag_rotate)) {
// 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++) {
ai->apply_force(rot_inv.rotate(force * ai->grad));
ai->apply_force(rot_inv * (force * ai->grad));
}
} else {
@ -1418,9 +1454,9 @@ void cvm::atom_group::apply_force(cvm::rvector const &force)
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++) {
ai->apply_force(rot_inv.rotate((ai->mass/total_mass) * force));
ai->apply_force(rot_inv * ((ai->mass/total_mass) * force));
}
} else {

View File

@ -15,6 +15,9 @@
#include "colvarparse.h"
#include "colvardeps.h"
template <typename T1, typename T2>
struct rotation_derivative;
/// \brief Stores numeric id, mass and all mutable data for an atom,
/// mostly used by a \link colvar::cvc \endlink
@ -167,7 +170,7 @@ public:
atom_group(std::vector<cvm::atom> const &atoms_in);
/// \brief Destructor
~atom_group();
~atom_group() override;
/// \brief Optional name to reuse properties of this in other groups
std::string name;
@ -180,7 +183,7 @@ public:
int init();
/// \brief Initialize dependency tree
virtual int init_dependencies();
int init_dependencies() override;
/// \brief Update data required to calculate cvc's
int setup();
@ -221,16 +224,13 @@ public:
static std::vector<feature *> ag_features;
/// \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;
}
virtual std::vector<feature *> &modify_features()
{
return ag_features;
}
static void delete_features() {
for (size_t i=0; i < ag_features.size(); i++) {
for (size_t i = 0; i < ag_features.size(); i++) {
delete ag_features[i];
}
ag_features.clear();
@ -330,6 +330,9 @@ public:
/// The rotation calculated automatically if f_ag_rotate is defined
cvm::rotation rot;
/// Rotation derivative;
rotation_derivative<cvm::atom, cvm::atom_pos>* rot_deriv;
/// \brief Indicates that the user has explicitly set centerToReference or
/// rotateReference, and the corresponding reference:
/// cvc's (eg rmsd, eigenvector) will not override the user's choice
@ -369,6 +372,8 @@ public:
/// \brief (Re)calculate the optimal roto-translation
void calc_apply_roto_translation();
void setup_rotation_derivative();
/// \brief Save aside the center of geometry of the reference positions,
/// then subtract it from them
///
@ -492,6 +497,16 @@ public:
/// \brief Calculate the derivatives of the fitting transformation
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
std::vector<cvm::atom_pos> fit_gradients;
@ -525,7 +540,7 @@ public:
/// Implements possible actions to be carried out
/// when a given feature is enabled
/// 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 "colvarbias.h"
#include "colvargrid.h"
#include "colvars_memstream.h"
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);
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);
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);
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
for (i = 0; i < colvardeps::f_cvb_ntot; i++) {
if (is_not_set(i)) {
@ -202,7 +209,7 @@ int colvarbias::init_dependencies() {
// Initialize feature_states for each instance
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));
// Most features are available, so we set them so
// and list exceptions below
@ -436,42 +443,54 @@ int colvarbias::bin_num()
cvm::error("Error: bin_num() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
int colvarbias::current_bin()
{
cvm::error("Error: current_bin() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
int colvarbias::bin_count(int /* bin_index */)
{
cvm::error("Error: bin_count() not implemented.\n");
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()
{
cvm::error("Error: replica_share() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
size_t colvarbias::replica_share_freq() const
{
return 0;
}
std::string const colvarbias::get_state_params() const
{
std::ostringstream os;
os << "step " << cvm::step_absolute() << "\n"
<< "name " << this->name << "\n";
os << " step " << cvm::step_absolute() << "\n"
<< " name " << this->name << "\n";
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 = "";
colvarparse::get_keyval(conf, "name", check_name,
std::string(""), colvarparse::parse_silent);
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);
}
@ -480,11 +499,17 @@ int colvarbias::set_state_params(std::string const &conf)
cvm::log("Ignoring state of bias \""+check_name+
"\": 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,
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)
{
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.precision(cvm::cv_prec);
os << state_keyword << " {\n"
<< " configuration {\n";
std::istringstream is(get_state_params());
std::string line;
while (std::getline(is, line)) {
os << " " << line << "\n";
}
os << " }\n";
<< " configuration {\n"
<< get_state_params()
<< " }\n";
write_state_data(os);
os << "}\n\n";
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;
if ( !(is >> key) || !(key == state_keyword || key == bias_type) ||
!(is >> brace) || !(brace == "{") ||
!(is >> colvarparse::read_block("configuration", &conf)) ||
(set_state_params(conf) != COLVARS_OK) ) {
cvm::error("Error: in reading state configuration 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);
if (is >> key) {
if (key == state_keyword || key == bias_type) {
if (! std::is_same<IST, cvm::memory_stream>::value) {
// Formatted input only
if (!(is >> brace) || !(brace == "{") ) {
raise_error_rewind(is, start_pos, bias_type, name);
return is;
}
}
if (!(is >> colvarparse::read_block("configuration", &conf)) ||
(check_matching_state(conf) != COLVARS_OK)) {
raise_error_rewind(is, start_pos, bias_type, name);
return is;
}
if (matching_state == false) {
// This state is not for this bias
is.seekg(start_pos, std::ios::beg);
} else {
// Not a match for this bias type, rewind without error
is.seekg(start_pos);
return is;
}
cvm::log("Restarting "+bias_type+" bias \""+name+"\" from step number "+
cvm::to_str(state_file_step)+".\n");
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);
} else {
raise_error_rewind(is, start_pos, bias_type, name);
return is;
}
if (!matching_state) {
// No errors, but not a match for this bias instance; rewind
is.seekg(start_pos);
return is;
}
if ((set_state_params(conf) != COLVARS_OK) || !read_state_data(is)) {
raise_error_rewind(is, start_pos, bias_type, name);
}
if (! std::is_same<IST, cvm::memory_stream>::value) {
is >> brace;
if (brace != "}") {
cvm::error("Error: corrupt restart information for \""+bias_type+"\" bias \""+
this->name+"\": no matching brace at position "+
cvm::to_str(static_cast<size_t>(is.tellg()))+
" in stream.\n");
is.setstate(std::ios::failbit);
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;
}
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)
{
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;
if ( !(is >> key_in) ||
!(to_lower_cppstr(key_in) == to_lower_cppstr(std::string(key))) ) {
cvm::error("Error: in reading restart configuration 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);
return is;
if (is >> key_in) {
if (key_in != key) {
raise_error_rewind(is, start_pos, bias_type, name,
" Expected keyword \"" + std::string(key) + "\", found \"" + key_in +
"\".");
}
} else {
raise_error_rewind(is, start_pos, bias_type, name);
}
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)
{
@ -686,28 +780,11 @@ colvarbias_ti::colvarbias_ti(char const *key)
// Samples at step zero can not be collected
feature_states[f_cvb_step_zero_data].available = false;
}
ti_avg_forces = NULL;
ti_count = NULL;
}
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()
{
if (is_enabled(f_cvb_calc_ti_samples)) {
if (ti_avg_forces == NULL) {
if (!ti_avg_forces) {
ti_bin.resize(num_variables());
ti_system_forces.resize(num_variables());
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].reset();
}
ti_avg_forces = new colvar_grid_gradient(colvars);
ti_count = new colvar_grid_count(colvars);
ti_avg_forces.reset(new colvar_grid_gradient(colvars));
ti_count.reset(new colvar_grid_count(colvars));
ti_avg_forces->samples = ti_count;
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)) {
return os;
}
os << "\nhistogram\n";
write_state_data_key(os, "histogram");
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);
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 error_code = COLVARS_OK;

View File

@ -10,6 +10,8 @@
#ifndef COLVARBIAS_H
#define COLVARBIAS_H
#include <memory>
#include "colvar.h"
#include "colvarparse.h"
#include "colvardeps.h"
@ -91,11 +93,16 @@ public:
// FIXME this is currently 1D only
virtual int current_bin();
//// Give the count at a given bin index.
// FIXME this is currently 1D only
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.
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
virtual void analyze() {}
@ -133,32 +140,87 @@ public:
/// Write the values of specific mutable properties to a string
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
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)
{
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)
{
return is;
}
/// Read a keyword from the state data (typically a header)
/// \param Input stream
/// \param Keyword labeling the header block
std::istream & read_state_data_key(std::istream &is, char const *key);
/// Read all mutable data not already set by set_state_params() from an unformatted stream
virtual cvm::memory_stream & read_state_data(cvm::memory_stream &is)
{
return is;
}
/// Write the bias configuration to a state file or other stream
std::ostream & write_state(std::ostream &os);
/// Write a keyword header for a data sequence to a formatted stream
/// \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);
/// 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
int write_state_prefix(std::string const &prefix);
@ -274,8 +336,6 @@ public:
colvarbias_ti(char const *key);
virtual ~colvarbias_ti();
virtual int clear_state_data();
virtual int init(std::string const &conf);
virtual int init_grids();
virtual int update();
@ -288,7 +348,9 @@ public:
virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &state_conf);
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);
virtual int write_output_files();
protected:
@ -297,10 +359,10 @@ protected:
std::vector<colvarvalue> ti_system_forces;
/// Averaged system forces
colvar_grid_gradient *ti_avg_forces;
std::shared_ptr<colvar_grid_gradient> ti_avg_forces;
/// 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,
/// 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 <sstream>
#include <iomanip>
#include <memory>
#include "colvarproxy.h"
#include "colvarbias.h"
#include "colvargrid.h"
#include "colvar_UIestimator.h"
typedef cvm::real* gradient_t;
typedef cvm::real *gradient_t;
/// ABF bias
@ -31,17 +32,14 @@ public:
/// Constructor for ABF bias
colvarbias_abf(char const *key);
/// Initializer for ABF bias
virtual int init(std::string const &conf);
int init(std::string const &conf) override;
/// Default destructor for ABF bias
virtual ~colvarbias_abf();
~colvarbias_abf() override;
/// Per-timestep update of ABF bias
virtual int update();
int update() override;
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)
std::vector<std::string> input_prefix;
@ -57,8 +55,8 @@ private:
size_t full_samples;
/// Number of samples per bin before applying a scaled-down biasing force
size_t min_samples;
/// Write combined files with a history of all output data?
bool b_history_files;
/// Latest absolute time step at which history files were written
cvm::step_number history_last_step;
/// Write CZAR output file for stratified eABF (.zgrad)
bool b_czar_window_file;
/// Number of timesteps between recording data in history files (if non-zero)
@ -99,75 +97,104 @@ private:
gradient_t system_force;
/// 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
colvar_grid_count *samples;
std::shared_ptr<colvar_grid_count> samples;
/// 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
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
colvar_grid_count *z_samples;
/// n-dim grid containing CZAR estimator of "real" free energy gradients
colvar_grid_gradient *czar_gradients;
std::shared_ptr<colvar_grid_count> z_samples;
/// n-dim grid containing CZAR estimatr of "real" free energy gradients
std::shared_ptr<colvar_grid_gradient> czar_gradients;
/// 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)
{
if (colvars[i]->is_enabled(f_cv_subtract_applied_force)) {
// this colvar is already subtracting the ABF force
system_force[i] = colvars[i]->total_force().real_value;
} else {
system_force[i] = colvars[i]->total_force().real_value
- colvar_forces[i].real_value;
// 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;
}
/// Calculate system force for all colvars
int update_system_force();
/// Calulate the biasing force for the current bin
int calc_biasing_force(std::vector<cvm::real> &force);
/// Calulate the smoothing factor to apply to biasing forces for given local count
cvm::real smoothing_factor(cvm::real weight);
// shared ABF
bool shared_on;
size_t shared_freq;
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
colvar_grid_gradient *last_gradients;
colvar_grid_count *last_samples;
// Share between replicas -- may be called independently of update
int replica_share() override;
// 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.
/// 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.
virtual int current_bin();
int current_bin() override;
//// 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
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)
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,
std::string const &name,
bool close);
virtual std::istream& read_state_data(std::istream&);
virtual std::ostream& write_state_data(std::ostream&);
virtual int write_output_files();
private:
/// 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
virtual int calc_energy(std::vector<colvarvalue> const *values);
int calc_energy(std::vector<colvarvalue> const *values) override;
};
#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 <iomanip>
#include <cstdlib>
#include "colvarmodule.h"
#include "colvarproxy.h"
@ -40,7 +39,10 @@ colvarbias_alb::colvarbias_alb(char const *key)
int colvarbias_alb::init(std::string const &conf)
{
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");
enable(f_cvb_scalar_variables);

View File

@ -7,10 +7,13 @@
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <iostream>
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvar.h"
#include "colvarbias_histogram.h"
#include "colvars_memstream.h"
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)
{
colvarbias::init(conf);
int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
cvm::main()->cite_feature("Histogram colvar bias implementation");
enable(f_cvb_scalar_variables);
@ -125,22 +131,6 @@ int colvarbias_histogram::update()
// assign a valid bin size
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) {
// update indices for scalar values
size_t i;
@ -181,6 +171,16 @@ int colvarbias_histogram::write_output_files()
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") {
cvm::log("Writing the histogram file \""+out_name+"\".\n");
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)
{
if (! read_state_data_key(is, "grid")) {
return is;
if (read_state_data_key(is, "grid")) {
grid->read_raw(is);
}
if (! grid->read_raw(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;
}
@ -212,8 +217,16 @@ std::ostream & colvarbias_histogram::write_state_data(std::ostream& os)
{
std::ios::fmtflags flags(os.flags());
os.setf(std::ios::fmtflags(0), std::ios::floatfield);
os << "grid\n";
write_state_data_key(os, "grid");
grid->write_raw(os, 8);
os.flags(flags);
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:
colvarbias_histogram(char const *key);
~colvarbias_histogram();
virtual ~colvarbias_histogram();
virtual int init(std::string const &conf);
virtual int update();
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:
/// n-dim histogram
@ -40,9 +45,6 @@ protected:
size_t colvar_array_size;
/// If colvar_array_size is larger than 1, weigh each one by this number before accumulating the histogram
std::vector<cvm::real> weights;
virtual std::istream & read_state_data(std::istream &is);
virtual std::ostream & write_state_data(std::ostream &os);
};
#endif

View File

@ -9,6 +9,7 @@
#include "colvarbias_histogram_reweight_amd.h"
#include "colvarproxy.h"
#include "colvars_memstream.h"
colvarbias_reweightaMD::colvarbias_reweightaMD(char const *key)
: 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());
os.setf(std::ios::fmtflags(0), std::ios::floatfield);
os << "grid\n";
write_state_data_key(os, "grid");
grid->write_raw(os, 8);
os << "grid_count\n";
write_state_data_key(os, "grid_count");
grid_count->write_raw(os, 8);
os << "grid_dV\n";
write_state_data_key(os, "grid_dV");
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);
os.flags(flags);
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")) {
return is;
@ -387,3 +402,15 @@ std::istream & colvarbias_reweightaMD::read_state_data(std::istream& 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:
colvarbias_reweightaMD(char const *key);
virtual ~colvarbias_reweightaMD();
#if (__cplusplus >= 201103L)
virtual int init(std::string const &conf) override;
virtual int update() 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
/// it with -1/beta
@ -85,14 +79,15 @@ protected:
/// Write gradients of the PMF?
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
#if (__cplusplus >= 201103L)
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;
#else
virtual std::istream & read_state_data(std::istream &is);
virtual std::ostream & write_state_data(std::ostream &os);
#endif
virtual cvm::memory_stream & write_state_data(cvm::memory_stream &os) override;
private:
/// temporary grids for evaluating PMFs
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
// Colvars repository at GitHub.
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#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__)
#include <direct.h>
#define CHDIR ::_chdir
#define GETCWD ::_getcwd
#define GETCWD(BUF, SIZE) ::_getcwd(BUF, SIZE)
#define PATHSEP "\\"
#else
#include <unistd.h>
#define CHDIR ::chdir
#define GETCWD ::getcwd
#define GETCWD(BUF, SIZE) ::getcwd(BUF, SIZE)
#define PATHSEP "/"
#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 "colvarproxy.h"
#include "colvar.h"
#include "colvarbias_meta.h"
#include "colvars_memstream.h"
colvarbias_meta::colvarbias_meta(char const *key)
@ -58,7 +62,6 @@ colvarbias_meta::colvarbias_meta(char const *key)
ebmeta_equil_steps = 0L;
replica_update_freq = 0;
replica_id.clear();
}
@ -392,11 +395,8 @@ colvarbias_meta::add_hill(colvarbias_meta::hill const &h)
// output to trajectory (if specified)
if (b_hills_traj) {
// Open trajectory file or access the one already open
std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name());
hills_traj_os << (hills.back()).output_traj();
cvm::proxy->flush_output_stream(hills_traj_file_name());
// Save the current hill to a buffer for further traj output
hills_traj_os_buf << (hills.back()).output_traj();
}
has_data = true;
@ -427,13 +427,10 @@ colvarbias_meta::delete_hill(hill_iter &h)
}
if (b_hills_traj) {
// output to the trajectory
std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name());
hills_traj_os << "# DELETED this hill: "
// Save the current hill to a buffer for further traj output
hills_traj_os_buf << "# DELETED this hill: "
<< (hills.back()).output_traj()
<< "\n";
cvm::proxy->flush_output_stream(hills_traj_file_name());
}
return hills.erase(h);
@ -624,9 +621,9 @@ int colvarbias_meta::update_bias()
add_hill(hill(cvm::step_absolute(), hill_weight*hills_scale,
colvar_values, colvar_sigmas, replica_id));
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) {
replica_hills_os << hills.back();
write_hill(replica_hills_os, hills.back());
} else {
return cvm::error("Error: in metadynamics bias \""+this->name+"\""+
((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 error_code = COLVARS_OK;
colvarproxy *proxy = cvm::proxy;
// sync with the other replicas (if needed)
if (comm == multiple_replicas) {
colvarproxy *proxy = cvm::main()->proxy;
// reread the replicas registry
error_code |= update_replicas_registry();
// 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 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 (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_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);
}
std::streampos const hills_energy_pos = is.tellg();
std::string key;
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_pos, std::ios::beg);
is.setstate(std::ios::failbit);
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;
}
}
}
read_grid_data_template_<IST, colvar_grid_scalar>(is, "hills_energy", hills_energy,
hills_energy_backup);
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");
read_grid_data_template_<IST, colvar_grid_gradient>(
is, "hills_energy_gradients", hills_energy_gradients, hills_energy_gradients_backup);
if (is) {
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;
}
} else {
return is;
}
}
// Save references to the end of the list of existing hills, so that it can
// be cleared if hills are read successfully state
// Save references to the end of the list of existing hills, so that they can
// be cleared if hills are read successfully from the stream
bool const existing_hills = !hills.empty();
size_t const old_hills_size = hills.size();
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)) {
if (cvm::debug()) {
cvm::log("Read a previously saved hill under the "
"metadynamics bias \""+
this->name+"\", created at step "+
cvm::to_str((hills.back()).it)+".\n");
"metadynamics bias \"" +
this->name + "\", created at step " + cvm::to_str((hills.back()).it) +
"; position in stream is " + cvm::to_str(is.tellg()) + ".\n");
}
}
is.clear();
new_hills_begin = hills.end();
cvm::log(" read "+cvm::to_str(hills.size() - old_hills_size)+
" additional explicit hills.\n");
cvm::log(" successfully read "+cvm::to_str(hills.size() - old_hills_size)+
" explicit hills from state.\n");
if (existing_hills) {
// Prune any hills that pre-existed those just read
hills.erase(hills.begin(), old_hills_end);
hills_off_grid.erase(hills_off_grid.begin(), old_hills_off_grid_end);
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) {
// 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()) {
std::ostringstream tmp_os;
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";
new_hills_energy->write_params(tmp_os);
tmp_os << new_hills_energy->get_state_params();
cvm::log(tmp_os.str());
}
@ -1495,96 +1491,150 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
if (!hills.empty())
recount_hills_off_grid(hills.begin(), hills.end(), hills_energy);
}
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 != single_replica) {
read_replica_files();
}
return is;
}
inline std::istream & reset_istream(std::istream &is, size_t start_pos)
template <typename OST>
OST &colvarbias_meta::write_hill_template_(OST &os, colvarbias_meta::hill const &h)
{
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, std::ios::beg);
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;
}
std::istream & colvarbias_meta::read_hill(std::istream &is)
template <typename IST> IST &colvarbias_meta::read_hill_template_(IST &is)
{
if (!is) return is; // do nothing if failbit is set
if (!is)
return is; // do nothing if failbit is set
std::streampos const start_pos = is.tellg();
size_t i = 0;
bool const formatted = !std::is_same<IST, cvm::memory_stream>::value;
std::string data;
if ( !(is >> read_block("hill", &data)) ) {
return reset_istream(is, start_pos);
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;
}
std::istringstream data_is(data);
if (formatted) {
std::string brace;
if (!(is >> brace) || (brace != "{")) {
return hill_stream_error<IST>(is, start_pos, "hill");
}
}
cvm::step_number h_it = 0L;
cvm::real h_weight;
cvm::real h_weight = 0.0;
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());
}
std::vector<cvm::real> h_sigmas(num_variables());
std::string h_replica;
std::string keyword;
while (data_is >> keyword) {
if (keyword == "step") {
if ( !(data_is >> h_it)) {
return reset_istream(is, start_pos);
if (!read_state_data_key(is, "step") || !(is >> h_it)) {
return hill_stream_error<IST>(is, start_pos, "step");
}
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 \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n");
return is;
if (read_state_data_key(is, "weight")) {
if (!(is >> h_weight)) {
return hill_stream_error<IST>(is, start_pos, "weight");
}
}
if (keyword == "weight") {
if ( !(data_is >> h_weight)) {
return reset_istream(is, start_pos);
}
}
if (keyword == "centers") {
for (i = 0; i < num_variables(); i++) {
if ( !(data_is >> h_centers[i])) {
return reset_istream(is, start_pos);
if (read_state_data_key(is, "centers")) {
for (size_t i = 0; i < num_variables(); i++) {
if (!(is >> h_centers[i])) {
return hill_stream_error<IST>(is, start_pos, "centers");
}
}
}
if (keyword == "widths") {
for (i = 0; i < num_variables(); i++) {
if ( !(data_is >> h_sigmas[i])) {
return reset_istream(is, start_pos);
if (read_state_data_key(is, "widths")) {
for (size_t i = 0; i < num_variables(); i++) {
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;
@ -1592,17 +1642,31 @@ std::istream & colvarbias_meta::read_hill(std::istream &is)
}
if (comm != single_replica) {
if (keyword == "replicaID") {
if ( !(data_is >> h_replica)) {
return reset_istream(is, start_pos);
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);
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 (formatted) {
std::string brace;
if (!(is >> brace) || (brace != "}")) {
return hill_stream_error<IST>(is, start_pos, "hill");
}
}
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 \"" + this->name +
"\"" + ((comm != single_replica) ? ", replica \"" + replica_id + "\"" : "") + "\n");
return is;
}
hill_iter const hills_end = hills.end();
@ -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 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?
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",
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
// 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) {
list_os << "stateFile " << replica_state_file << "\n";
list_os << "hillsFile " << replica_hills_file << "\n";
@ -1723,7 +1802,7 @@ int colvarbias_meta::setup_output()
if (b_hills_traj) {
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) {
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) {
// this is a very good time to project hills, if you haven't done
// it already!
project_hills(new_hills_begin, hills.end(),
hills_energy, hills_energy_gradients);
project_hills(new_hills_begin, hills.end(), hills_energy, hills_energy_gradients);
new_hills_begin = hills.end();
// write down the grids to the restart file
os << " hills_energy\n";
write_state_data_key(os, "hills_energy");
hills_energy->write_restart(os);
os << " hills_energy_gradients\n";
write_state_data_key(os, "hills_energy_gradients");
hills_energy_gradients->write_restart(os);
}
if ( (!use_grids) || keep_hills ) {
if ((!use_grids) || keep_hills) {
// write all hills currently in memory
for (std::list<hill>::const_iterator h = this->hills.begin();
h != this->hills.end();
h++) {
os << *h;
for (std::list<hill>::const_iterator h = this->hills.begin(); h != this->hills.end(); h++) {
write_hill(os, *h);
}
} else {
// write just those that are near the grid boundaries
for (std::list<hill>::const_iterator h = this->hills_off_grid.begin();
h != this->hills_off_grid.end();
h++) {
os << *h;
h != this->hills_off_grid.end(); h++) {
write_hill(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 error_code = COLVARS_OK;
@ -1816,6 +1903,15 @@ int colvarbias_meta::write_output_files()
if (dump_fes) {
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;
}
@ -1915,7 +2011,7 @@ int colvarbias_meta::write_replica_state_file()
// Write to temporary state file
std::string const tmp_state_file(replica_state_file+".tmp");
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 (!write_state(rep_state_os)) {
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;
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->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) {
replica_hills_os.setf(std::ios::scientific, std::ios::floatfield);
} else {
@ -2037,43 +2133,3 @@ colvarbias_meta::hill::operator = (colvarbias_meta::hill const &h)
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 "colvargrid.h"
/// Metadynamics bias (implementation of \link colvarbias \endlink)
class colvarbias_meta
: public virtual colvarbias,
@ -51,14 +52,32 @@ public:
virtual int update_bias();
virtual int update_grid_data();
virtual int replica_share();
virtual size_t replica_share_freq() const;
virtual int calc_energy(std::vector<colvarvalue> const *values);
virtual int calc_forces(std::vector<colvarvalue> const *values);
virtual std::string const get_state_params() const;
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 write_output_files();
@ -107,9 +126,22 @@ protected:
void recount_hills_off_grid(hill_iter h_first, hill_iter h_last,
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);
/// 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,
/// write it there; if there is more than one replica, communicate
/// it to the others
@ -230,7 +262,7 @@ protected:
std::vector<colvarbias_meta *> replicas;
/// \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
/// copied into replicas_registry for convenience
@ -258,6 +290,8 @@ protected:
/// Position within replica_hills_file (when reading it)
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
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)
{
colvarbias::init(conf);
int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
enable(f_cvb_apply_force);
colvarbias_ti::init(conf);
@ -202,6 +205,8 @@ int colvarbias_restraint_moving::init(std::string const &conf)
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);
if (!target_nsteps) {
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;
os.setf(std::ios::scientific, std::ios::floatfield);
if (b_chg_centers || b_chg_force_k) {
// TODO move this
os << "firstStep " << std::setw(cvm::it_width) << first_step << "\n";
if (target_nstages) {
os << "stage " << std::setw(cvm::it_width)
<< stage << "\n";
os << "stage " << std::setw(cvm::it_width) << stage << "\n";
}
}
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)
{
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) {
get_keyval(conf, "stage", stage, stage,
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)
{
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)
{
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)
{
colvarbias_restraint::write_traj_label(os);
@ -1338,7 +1312,10 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
{
int error_code = COLVARS_OK;
colvarbias::init(conf);
int err = colvarbias::init(conf);
if (err != COLVARS_OK) {
return err;
}
enable(f_cvb_apply_force);
cvm::main()->cite_feature("histogramRestraint colvar bias implementation");

View File

@ -38,9 +38,6 @@ public:
virtual std::string const get_state_params() const;
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(std::ostream &os);
@ -242,8 +239,6 @@ public:
virtual int update();
virtual std::string const get_state_params() const;
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(std::ostream &os);
virtual int change_configuration(std::string const &conf);
@ -269,8 +264,6 @@ public:
virtual int update();
virtual std::string const get_state_params() const;
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(std::ostream &os);
@ -311,8 +304,6 @@ public:
virtual std::string const get_state_params() const;
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(std::ostream &os);

View File

@ -19,45 +19,40 @@
colvar::cvc::cvc()
{
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();
}
colvar::cvc::cvc(std::string const &conf)
int colvar::cvc::update_description()
{
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;
init_dependencies();
colvar::cvc::init(conf);
if (name.size() > 0) {
description = "cvc \"" + name + "\"";
} else {
description = "unnamed cvc";
}
description += " of type \"" + function_type() + "\"";
return COLVARS_OK;
}
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)
{
function_type = type;
if (function_types.size() == 0) {
function_types.push_back(function_type);
} else {
if (function_types.back() != function_type) {
function_types.push_back(function_type);
}
}
function_types.push_back(type);
update_description();
cvm::main()->cite_feature(function_types[0]+" colvar component");
for (size_t i = function_types.size()-1; i > 0; i--) {
cvm::main()->cite_feature(function_types[i]+" colvar component"+
" (derived from "+function_types[i-1]+")");
}
cvm::main()->cite_feature(function_types[0]+" colvar component");
return COLVARS_OK;
}
@ -67,6 +62,8 @@ int colvar::cvc::init(std::string const &conf)
if (cvm::debug())
cvm::log("Initializing cvc base object.\n");
int error_code = COLVARS_OK;
std::string const old_name(name);
if (name.size() > 0) {
@ -74,18 +71,14 @@ int colvar::cvc::init(std::string const &conf)
}
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)) {
cvm::error("Error: cannot rename component \""+old_name+
"\" after initialization (new name = \""+name+"\")",
error_code |= cvm::error("Error: cannot rename component \"" + old_name +
"\" after initialization (new name = \"" + name + "\")",
COLVARS_INPUT_ERROR);
name = old_name;
}
}
update_description();
get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff);
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("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",
f_cvc_debug_gradient, false, parse_silent);
@ -119,7 +130,7 @@ int colvar::cvc::init(std::string const &conf)
if (cvm::debug())
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,
bool optional)
{
cvm::atom_group *group = NULL;
int error_code = COLVARS_OK;
cvm::atom_group *group = nullptr;
std::string group_conf;
if (key_lookup(conf, group_key, &group_conf)) {
group = new cvm::atom_group(group_key);
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
}
if (group_conf.size() == 0) {
cvm::error("Error: atom group \""+group->key+
"\" is set, but has no definition.\n",
if (group_conf.empty()) {
error_code |= cvm::error("Error: atom group \"" + group->key + "\" has no definition.\n",
COLVARS_INPUT_ERROR);
delete group;
group = nullptr;
// Silence unused variable warning; TODO stop returning a pointer
(void) error_code;
return group;
}
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);
}
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);
error_code |= group->check_keywords(group_conf, group_key);
}
cvm::decrease_depth();
} else {
if (! optional) {
cvm::error("Error: definition for atom group \""+
std::string(group_key)+"\" not found.\n");
if (!optional) {
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;
}
@ -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_explicit_atom_groups, "explicit_atom_groups", f_type_static);
init_feature(f_cvc_gradient, "gradient", f_type_dynamic);
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);
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
// require_feature_children(f_cvc_scalable, f_ag_scalable);
@ -281,7 +309,7 @@ int colvar::cvc::init_dependencies() {
// default as available, not enabled
// except dynamic features which default as unavailable
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;
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_collect_atom_ids].available = true;
feature_states[f_cvc_periodic].available = false;
// CVCs are enabled from the start - get disabled based on flags
enable(f_cvc_active);
@ -314,7 +344,7 @@ int colvar::cvc::init_dependencies() {
int colvar::cvc::setup()
{
description = "cvc " + name;
update_description();
return COLVARS_OK;
}
@ -349,6 +379,7 @@ void colvar::cvc::init_as_angle()
void colvar::cvc::init_as_periodic_angle()
{
x.type(colvarvalue::type_scalar);
provide(f_cvc_periodic);
enable(f_cvc_periodic);
period = 360.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);
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()
{
size_t ig;
for (ig = 0; ig < atom_groups.size(); ig++) {
cvm::atom_group &atoms = *(atom_groups[ig]);
if (is_enabled(f_cvc_explicit_atom_groups)) {
for (auto agi = atom_groups.begin(); agi != atom_groups.end(); agi++) {
cvm::atom_group &atoms = *(*agi);
atoms.reset_atoms_data();
atoms.read_positions();
atoms.calc_required_properties();
// 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();
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
// gradient in the laboratory frame
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++) {
size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
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 {
@ -494,7 +518,7 @@ void colvar::cvc::collect_gradients(std::vector<int> const &atom_ids, std::vecto
void colvar::cvc::calc_force_invgrads()
{
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);
}
@ -502,7 +526,7 @@ void colvar::cvc::calc_force_invgrads()
void colvar::cvc::calc_Jacobian_derivative()
{
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);
}
@ -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()
{
// this function should work for any scalar cvc:
@ -528,8 +564,8 @@ void colvar::cvc::debug_gradients()
cvm::atom_group *group = atom_groups[ig];
if (group->b_dummy) continue;
cvm::rotation const rot_0 = group->rot;
cvm::rotation const rot_inv = group->rot.inverse();
const auto rot_0 = group->rot.matrix();
const auto rot_inv = group->rot.inverse().matrix();
cvm::real x_0 = x.real_value;
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::to_str(j) + "] = " +
(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])));
}
}
@ -561,7 +597,7 @@ void colvar::cvc::debug_gradients()
// tests are best conducted in the unrotated (simulation) frame
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);
gradient_sum += atom_grad;
@ -634,34 +670,43 @@ void colvar::cvc::debug_gradients()
}
cvm::real colvar::cvc::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
cvm::real colvar::cvc::dist2(colvarvalue const &x1, 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 const &x2) const
colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1, 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 const &x2) const
colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1, 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
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 "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
colvar::alch_lambda::alch_lambda(std::string const &conf)
: cvc(conf)
colvar::alch_lambda::alch_lambda()
{
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);
}
simple_scalar_dist_functions(alch_lambda)
colvar::alch_Flambda::alch_Flambda(std::string const &conf)
: cvc(conf)
colvar::alch_Flambda::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;
}
simple_scalar_dist_functions(alch_Flambda)

View File

@ -12,8 +12,7 @@
#include "colvarcomp.h"
colvar::angle::angle(std::string const &conf)
: cvc(conf)
colvar::angle::angle()
{
set_function_type("angle");
init_as_angle();
@ -21,26 +20,25 @@ colvar::angle::angle(std::string const &conf)
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
}
int colvar::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");
init_total_force_params(conf);
error_code |= init_total_force_params(conf);
return error_code;
}
colvar::angle::angle(cvm::atom const &a1,
cvm::atom const &a2,
cvm::atom const &a3)
colvar::angle::angle(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3) : angle()
{
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));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
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()
{
@ -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()
{
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)
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)
colvar::dihedral::dihedral()
{
set_function_type("dihedral");
init_as_periodic_angle();
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
}
int colvar::dihedral::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");
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,
cvm::atom const &a2,
cvm::atom const &a3,
colvar::dihedral::dihedral(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3,
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;
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()
{
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();
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;
cvm::rvector const dcosdA = rA*(cos_phi*A-B);
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);
@ -363,7 +301,7 @@ void colvar::dihedral::calc_gradients()
C *= rC;
cvm::rvector const dsindC = rC*(sin_phi*C-B);
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);
@ -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()
{
r = theta = phi = 0.0;
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()
{
r = theta = phi = 0.0;
set_function_type("polarPhi");
enable(f_cvc_com_based);
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()
{
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)),
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 <cmath>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <numeric>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.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");
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"));
std::vector<cvm::real> p_weights(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;
cvm::real p_lambda;
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);
cvm::log(std::string("Lambda is ") + cvm::to_str(lambda) + std::string("\n"));
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(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() {
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::aspathCV::~aspathCV() {}
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
// 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 (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);
computeDistanceBetweenReferenceFrames(rmsd_between_refs);
reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(lambda));
impl_->reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(impl_->get_lambda()));
}
computeValue();
x = s;
impl_->updateCVDistanceToReferenceFrames(this);
x = impl_->compute_s();
}
void colvar::aspathCV::calc_gradients() {
computeDerivatives();
impl_->compute_s_derivatives();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
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 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) {
(*(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 {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
colvarvalue cv_force = dsdx[i_cv] * force.real_value * factor_polynomial;
cv[i_cv]->apply_force(cv_force);
// compute the gradient (grad) with respect to the i-th CV
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];
}
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_->dsdx.size(); ++m_frame) {
analytical_grad += impl_->compute_s_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::aspathCV::~aspathCV() {}
colvar::azpathCV::azpathCV(std::string const &conf): CVBasedPath(conf) {
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));
x.type(colvarvalue::type_scalar);
use_explicit_gradients = true;
cvm::real p_lambda;
get_keyval(conf, "lambda", p_lambda, -1.0);
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"));
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(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);
}
}
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() {
if (lambda < 0) {
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 (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);
computeDistanceBetweenReferenceFrames(rmsd_between_refs);
reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(lambda));
impl_->reComputeLambda(rmsd_between_refs);
cvm::log("Ok, the value of lambda is updated to " + cvm::to_str(impl_->get_lambda()));
}
computeValue();
x = z;
impl_->updateCVDistanceToReferenceFrames(this);
x = impl_->compute_z();
}
void colvar::azpathCV::calc_gradients() {
computeDerivatives();
impl_->compute_z_derivatives();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
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 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) {
(*(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) {
// the PCV component itself is a scalar, so force should be scalar
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
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) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
}
} else {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
const colvarvalue cv_force = dzdx[i_cv] * force.real_value * factor_polynomial;
cv[i_cv]->apply_force(cv_force);
const 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());
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() {}
#endif

View File

@ -1,4 +1,4 @@
#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:
@ -9,14 +9,26 @@
#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
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())) {
std::vector<std::string> 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) {
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
if (cv.size() == 0) {
cvm::error("Error: the CV " + name +
" expects one or more nesting components.\n");
return;
return cvm::error("Error: the CV " + name + " expects one or more nesting components.\n",
COLVARS_INPUT_ERROR);
} 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.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;
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) {
disable(f_cvc_explicit_gradient);
}
return error_code;
}
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
std::string expr_in, expr;
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);
pexprs.push_back(pexpr);
} catch (...) {
cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
return cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
}
try {
value_evaluators.push_back(new Lepton::CompiledExpression(pexpr.createCompiledExpression()));
@ -178,7 +210,7 @@ colvar::customColvar::customColvar(std::string const &conf): linearCombination(c
}
}
} 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));
// 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) {
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) {
x.type(colvarvalue::type_vector);
@ -211,14 +243,17 @@ colvar::customColvar::customColvar(std::string const &conf): linearCombination(c
x.type(colvarvalue::type_scalar);
}
#else
cvm::error("customFunction requires the Lepton library, but it is not enabled during compilation.\n"
"Please refer to the Compilation Notes section of the Colvars manual for more information.\n",
COLVARS_INPUT_ERROR);
return cvm::error(
"customFunction requires the Lepton library, but it is not enabled during compilation.\n"
"Please refer to the Compilation Notes section of the Colvars manual for more "
"information.\n",
COLVARS_NOT_IMPLEMENTED);
#endif
} else {
cvm::log("Warning: no customFunction specified.\n");
cvm::log("Warning: use linear combination instead.\n");
}
return error_code;
}
colvar::customColvar::~customColvar() {
@ -317,7 +352,8 @@ void colvar::customColvar::apply_force(colvarvalue const &force) {
}
} else {
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);
for (size_t j_elem = 0; j_elem < current_cv_value.size(); ++j_elem) {
for (size_t c = 0; c < x.size(); ++c) {
@ -340,5 +376,3 @@ void colvar::customColvar::apply_force(colvarvalue const &force) {
#endif
}
}
#endif // __cplusplus >= 201103L

View File

@ -8,7 +8,6 @@
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvarparse.h"
#include "colvaratoms.h"
#include "colvarvalue.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)
: cvc(conf), b_anisotropic(false), pairlist(NULL)
colvar::coordnum::coordnum()
{
set_function_type("coordNum");
x.type(colvarvalue::type_scalar);
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");
group2 = parse_group(conf, "group2");
if (group1 == NULL || group2 == NULL) {
cvm::error("Error: failed to initialize atom groups.\n",
COLVARS_INPUT_ERROR);
return;
if (!group1 || !group2) {
return error_code | COLVARS_INPUT_ERROR;
}
if (int atom_number = cvm::atom_group::overlap(*group1, *group2)) {
cvm::error("Error: group1 and group2 share a common atom (number: " +
cvm::to_str(atom_number) + ")\n", COLVARS_INPUT_ERROR);
return;
error_code |= cvm::error(
"Error: group1 and group2 share a common atom (number: " + cvm::to_str(atom_number) + ")\n",
COLVARS_INPUT_ERROR);
}
if (group1->b_dummy) {
cvm::error("Error: only group2 is allowed to be a dummy atom\n",
COLVARS_INPUT_ERROR);
return;
error_code |=
cvm::error("Error: only group2 is allowed to be a dummy atom\n", COLVARS_INPUT_ERROR);
}
bool const b_isotropic = get_keyval(conf, "cutoff", r0,
cvm::real(proxy->angstrom_to_internal(4.0)));
bool const b_isotropic = get_keyval(conf, "cutoff", r0, r0);
if (get_keyval(conf, "cutoff3", r0_vec,
cvm::rvector(proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0),
proxy->angstrom_to_internal(4.0)))) {
if (get_keyval(conf, "cutoff3", r0_vec, r0_vec)) {
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",
COLVARS_INPUT_ERROR);
return;
}
b_anisotropic = true;
@ -141,16 +139,16 @@ colvar::coordnum::coordnum(std::string const &conf)
if (r0_vec.z < 0.0) r0_vec.z *= -1.0;
}
get_keyval(conf, "expNumer", en, 6);
get_keyval(conf, "expDenom", ed, 12);
get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, ed);
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);
}
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);
}
@ -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, "tolerance", tolerance, 0.0);
get_keyval(conf, "tolerance", tolerance, tolerance);
if (tolerance > 0) {
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) ) {
cvm::error("Error: non-positive pairlistfrequency provided.\n",
return cvm::error("Error: non-positive pairlistfrequency provided.\n",
COLVARS_INPUT_ERROR);
return; // and do not allocate the pairlists below
// return and do not allocate the pairlists below
}
if (b_group2_center_only) {
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() *
group2->size()));
return error_code;
}
colvar::coordnum::~coordnum()
{
if (pairlist != NULL) {
if (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
colvar::h_bond::h_bond(std::string const &conf)
: cvc(conf)
colvar::h_bond::h_bond()
{
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())
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);
init_scalar_boundaries(0.0, 1.0);
colvarproxy *proxy = cvm::main()->proxy;
int a_num = -1, d_num = -1;
get_keyval(conf, "acceptor", a_num, a_num);
get_keyval(conf, "donor", d_num, a_num);
if ( (a_num == -1) || (d_num == -1) ) {
cvm::error("Error: either acceptor or donor undefined.\n");
return;
error_code |= cvm::error("Error: either acceptor or donor undefined.\n", COLVARS_INPUT_ERROR);
}
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(donor);
get_keyval(conf, "cutoff", r0, proxy->angstrom_to_internal(3.3));
get_keyval(conf, "expNumer", en, 6);
get_keyval(conf, "expDenom", ed, 8);
get_keyval(conf, "cutoff", r0, r0);
get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, ed);
if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
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) ) {
cvm::error("Error: negative exponent(s) provided.\n",
COLVARS_INPUT_ERROR);
if ((en <= 0) || (ed <= 0)) {
error_code |= cvm::error("Error: negative exponent(s) provided.\n", COLVARS_INPUT_ERROR);
}
if (cvm::debug())
cvm::log("Done initializing h_bond object.\n");
return error_code;
}
colvar::h_bond::h_bond(cvm::atom const &acceptor,
cvm::atom const &donor,
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");
x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0);
r0 = r0_i;
en = en_i;
ed = ed_i;
register_atom_group(new cvm::atom_group);
atom_groups[0]->add_atom(acceptor);
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);
}
simple_scalar_dist_functions(h_bond)
colvar::selfcoordnum::selfcoordnum(std::string const &conf)
: cvc(conf), pairlist(NULL)
colvar::selfcoordnum::selfcoordnum()
{
set_function_type("selfCoordNum");
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");
get_keyval(conf, "cutoff", r0, cvm::real(proxy->angstrom_to_internal(4.0)));
get_keyval(conf, "expNumer", en, 6);
get_keyval(conf, "expDenom", ed, 12);
if (!group1 || group1->size() == 0) {
return error_code | COLVARS_INPUT_ERROR;
}
get_keyval(conf, "cutoff", r0, r0);
get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, ed);
if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
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) ) {
cvm::error("Error: negative exponent(s) provided.\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)) {
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) {
get_keyval(conf, "pairListFrequency", pairlist_freq, 100);
get_keyval(conf, "pairListFrequency", pairlist_freq, pairlist_freq);
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);
return;
}
pairlist = new bool[(group1->size()-1) * (group1->size()-1)];
}
init_scalar_boundaries(0.0, static_cast<cvm::real>((group1->size()-1) *
(group1->size()-1)));
return error_code;
}
colvar::selfcoordnum::~selfcoordnum()
{
if (pairlist != NULL) {
if (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);
}
}
simple_scalar_dist_functions(selfcoordnum)
// groupcoordnum member functions
colvar::groupcoordnum::groupcoordnum(std::string const &conf)
: distance(conf), b_anisotropic(false)
colvar::groupcoordnum::groupcoordnum()
{
set_function_type("groupCoord");
x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0);
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()
if (group1->b_dummy || group2->b_dummy) {
cvm::error("Error: neither group can be a dummy atom\n");
return;
return cvm::error("Error: neither group can be a dummy atom\n", COLVARS_INPUT_ERROR);
}
bool const b_scale = get_keyval(conf, "cutoff", 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)) {
bool const b_scale = get_keyval(conf, "cutoff", r0, r0);
if (get_keyval(conf, "cutoff3", r0_vec, r0_vec)) {
if (b_scale) {
cvm::error("Error: cannot specify \"scale\" and "
"\"scale3\" at the same time.\n");
return;
error_code |=
cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" at the same time.\n",
COLVARS_INPUT_ERROR);
}
b_anisotropic = true;
// 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;
}
get_keyval(conf, "expNumer", en, 6);
get_keyval(conf, "expDenom", ed, 12);
get_keyval(conf, "expNumer", en, en);
get_keyval(conf, "expDenom", ed, ed);
if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
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) ) {
cvm::error("Error: negative exponent(s) provided.\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)) {
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);
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).
// The original version of Colvars and its updates are located at:
@ -10,17 +10,29 @@
#include <numeric>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <fstream>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.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
atoms = parse_group(conf, "atoms");
has_user_defined_fitting = false;
@ -31,13 +43,12 @@ colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(con
// Lookup reference column of PDB
// Copied from the RMSD class
std::string reference_column;
double reference_column_value;
double reference_column_value = 0.0;
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) {
cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n");
return;
return cvm::error("Error: refPositionsColValue, if provided, must be non-zero.\n",
COLVARS_INPUT_ERROR);
}
}
// 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->center_ref_pos();
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 {
// parse a group of atoms for fitting
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_fitting_group);
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);
}
tmp_atoms->setup_rotation_derivative();
comp_atoms.push_back(tmp_atoms);
}
}
x.type(colvarvalue::type_scalar);
// Don't use implicit gradient
enable(f_cvc_explicit_gradient);
return error_code;
}
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");
}
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);
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"));
@ -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"));
}
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;
return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) +
" 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);
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"));
return error_code;
}
void colvar::gspath::updateDistanceToReferenceFrames() {
@ -192,8 +252,9 @@ void colvar::gspath::prepareVectors() {
} else {
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) {
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 {
cvm::atom_pos reference_cog_1, reference_cog_3;
@ -227,9 +288,10 @@ void colvar::gspath::prepareVectors() {
} else {
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) {
// 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);
}
colvar::gzpath::gzpath(std::string const &conf): CartesianBasedPath(conf) {
colvar::gzpath::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);
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"));
@ -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"));
}
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;
return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) +
" 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);
// Logging
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"));
return error_code;
}
void colvar::gzpath::updateDistanceToReferenceFrames() {
@ -335,12 +408,13 @@ void colvar::gzpath::prepareVectors() {
} else {
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) {
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];
// v4 only computes in gzpath
// 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) {
v3 = v4;
@ -368,9 +442,10 @@ void colvar::gzpath::prepareVectors() {
} else {
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) {
// 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
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())) {
std::vector<std::string> 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) {
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"));
auto &ifs_path = cvm::main()->proxy->input_stream(path_filename);
if (!ifs_path) {
return;
return COLVARS_INPUT_ERROR;
}
std::string line;
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]));
}
} else {
cvm::error("Error: incorrect format of path file.\n");
return;
error_code = cvm::error("Error: incorrect format of path file.\n", COLVARS_INPUT_ERROR);
return error_code;
}
}
if (!fields.empty()) {
@ -461,15 +548,18 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
}
cvm::main()->proxy->close_input_stream(path_filename);
if (total_reference_frames <= 1) {
cvm::error("Error: there is only 1 or 0 reference frame, which doesn't constitute a path.\n");
return;
error_code = cvm::error(
"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) {
cvm::error("Error: the CV " + name +
" expects one or more nesting components.\n");
return;
error_code =
cvm::error("Error: the CV " + name + " expects one or more nesting components.\n",
COLVARS_INPUT_ERROR);
return error_code;
}
x.type(colvarvalue::type_scalar);
use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
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) {
disable(f_cvc_explicit_gradient);
}
return error_code;
}
void colvar::CVBasedPath::computeDistanceToReferenceFrames(std::vector<cvm::real>& result) {
@ -548,8 +640,47 @@ colvar::CVBasedPath::~CVBasedPath() {
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");
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"));
// Initialize variables for future calculation
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"));
}
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;
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);
}
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() {}
@ -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");
}
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"));
// Initialize variables for future calculation
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"));
}
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;
return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) +
" 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);
x.type(colvarvalue::type_scalar);
return error_code;
}
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 "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
#include "colvar_neuralnetworkcompute.h"
using namespace neuralnetworkCV;
colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination(conf) {
colvar::neuralNetwork::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
// read "output_component" key to determine it
get_keyval(conf, "output_component", m_output_index);
@ -59,8 +74,8 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
std::string function_name;
get_keyval(conf, lookup_key.c_str(), function_name, std::string(""));
if (activation_function_map.find(function_name) == activation_function_map.end()) {
cvm::error("Unknown activation function name: \"" + function_name + "\".\n");
return;
return cvm::error("Unknown activation function name: \"" + function_name + "\".\n",
COLVARS_INPUT_ERROR);
}
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');
@ -79,11 +94,13 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
}
// expect the three numbers are equal
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;
return cvm::error(
"Error: the numbers of weights, biases and activation functions do not match.\n",
COLVARS_INPUT_ERROR);
}
// nn = std::make_unique<neuralnetworkCV::neuralNetworkCompute>();
// std::make_unique is only available in C++14
if (nn) nn.reset();
nn = std::unique_ptr<neuralnetworkCV::neuralNetworkCompute>(new neuralnetworkCV::neuralNetworkCompute());
for (size_t i_layer = 0; i_layer < num_layers_weight; ++i_layer) {
denseLayer d;
@ -93,8 +110,9 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
try {
d = denseLayer(weight_files[i_layer], bias_files[i_layer], activation_functions[i_layer].second);
} catch (std::exception &ex) {
cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR);
return;
return cvm::error("Error on initializing layer " + cvm::to_str(i_layer) +
" (" + ex.what() + ")\n",
COLVARS_INPUT_ERROR);
}
} else {
#endif
@ -104,8 +122,9 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
try {
d = denseLayer(weight_files[i_layer], bias_files[i_layer], f, df);
} catch (std::exception &ex) {
cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR);
return;
return cvm::error("Error on initializing layer " + cvm::to_str(i_layer) +
" (" + ex.what() + ")\n",
COLVARS_INPUT_ERROR);
}
#ifdef LEPTON
}
@ -123,11 +142,11 @@ colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination
}
}
} else {
cvm::error("Error: error on adding a new dense layer.\n");
return;
return cvm::error("Error: error on adding a new dense layer.\n", COLVARS_INPUT_ERROR);
}
}
nn->input().resize(cv.size());
return error_code;
}
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 "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
colvar::alpha_angles::alpha_angles(std::string const &conf)
: cvc(conf)
colvar::alpha_angles::alpha_angles()
{
set_function_type("alpha");
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
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;
get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
@ -44,29 +48,29 @@ colvar::alpha_angles::alpha_angles(std::string const &conf)
}
}
} else {
cvm::error("Error: no residues defined in \"residueRange\".\n");
return;
error_code |=
cvm::error("Error: no residues defined in \"residueRange\".\n", COLVARS_INPUT_ERROR);
}
}
if (residues.size() < 5) {
cvm::error("Error: not enough residues defined in \"residueRange\".\n");
return;
error_code |= cvm::error("Error: not enough residues defined in \"residueRange\".\n",
COLVARS_INPUT_ERROR);
}
std::string const &sid = segment_id;
std::vector<int> const &r = residues;
get_keyval(conf, "hBondCoeff", hb_coeff, 0.5);
if ( (hb_coeff < 0.0) || (hb_coeff > 1.0) ) {
cvm::error("Error: hBondCoeff must be defined between 0 and 1.\n");
return;
get_keyval(conf, "hBondCoeff", hb_coeff, hb_coeff);
if ((hb_coeff < 0.0) || (hb_coeff > 1.0)) {
error_code |=
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, "angleTol", theta_tol, 15.0);
get_keyval(conf, "angleRef", theta_ref, theta_ref);
get_keyval(conf, "angleTol", theta_tol, theta_tol);
if (hb_coeff < 1.0) {
@ -84,11 +88,9 @@ colvar::alpha_angles::alpha_angles(std::string const &conf)
}
{
cvm::real r0;
size_t en, ed;
get_keyval(conf, "hBondCutoff", r0, proxy->angstrom_to_internal(3.3));
get_keyval(conf, "hBondExpNumer", en, 6);
get_keyval(conf, "hBondExpDenom", ed, 8);
get_keyval(conf, "hBondCutoff", r0, r0);
get_keyval(conf, "hBondExpNumer", en, en);
get_keyval(conf, "hBondExpDenom", ed, ed);
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");
}
}
}
colvar::alpha_angles::alpha_angles()
: cvc()
{
set_function_type("alphaAngles");
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
return error_code;
}
@ -273,24 +268,27 @@ void colvar::alpha_angles::apply_force(colvarvalue const &force)
}
simple_scalar_dist_functions(alpha_angles)
//////////////////////////////////////////////////////////////////////
// dihedral principal component
//////////////////////////////////////////////////////////////////////
colvar::dihedPC::dihedPC(std::string const &conf)
: cvc(conf)
colvar::dihedPC::dihedPC()
{
if (cvm::debug())
cvm::log("Initializing dihedral PC object.\n");
set_function_type("dihedPC");
// Supported through references to atom groups of children cvcs
enable(f_cvc_explicit_gradient);
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;
get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
@ -311,14 +309,14 @@ colvar::dihedPC::dihedPC(std::string const &conf)
}
}
} else {
cvm::error("Error: no residues defined in \"residueRange\".\n");
return;
error_code |=
cvm::error("Error: no residues defined in \"residueRange\".\n", COLVARS_INPUT_ERROR);
}
}
if (residues.size() < 2) {
cvm::error("Error: dihedralPC requires at least two residues.\n");
return;
error_code |=
cvm::error("Error: dihedralPC requires at least two residues.\n", COLVARS_INPUT_ERROR);
}
std::string const &sid = segment_id;
@ -329,15 +327,15 @@ colvar::dihedPC::dihedPC(std::string const &conf)
if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) {
get_keyval(conf, "vectorNumber", vecNumber, 0);
if (vecNumber < 1) {
cvm::error("A positive value of vectorNumber is required.");
return;
error_code |=
cvm::error("A positive value of vectorNumber is required.", COLVARS_INPUT_ERROR);
}
std::istream &vecFile =
cvm::main()->proxy->input_stream(vecFileName,
"dihedral PCA vector file");
if (!vecFile) {
return;
return COLVARS_INPUT_ERROR;
}
// 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)) {
cvm::error("Error: wrong number of coefficients: " +
cvm::to_str(coeffs.size()) + ". Expected " +
cvm::to_str(4 * (residues.size() - 1)) +
" (4 coeffs per residue, minus one residue).\n");
return;
error_code |= cvm::error("Error: wrong number of coefficients: " + cvm::to_str(coeffs.size()) +
". Expected " + cvm::to_str(4 * (residues.size() - 1)) +
" (4 coeffs per residue, minus one residue).\n",
COLVARS_INPUT_ERROR);
}
for (size_t i = 0; i < residues.size()-1; i++) {
@ -413,16 +410,8 @@ colvar::dihedPC::dihedPC(std::string const &conf)
if (cvm::debug())
cvm::log("Done initializing dihedPC object.\n");
}
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);
return error_code;
}
@ -491,6 +480,3 @@ void colvar::dihedPC::apply_force(colvarvalue const &force)
coeffs[2*i+1] * dsindt) * force);
}
}
simple_scalar_dist_functions(dihedPC)

View File

@ -9,27 +9,39 @@
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.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");
rot_deriv_impl = std::unique_ptr<rotation_derivative_impl_>(new rotation_derivative_impl_(this));
disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_quaternion);
colvar::orientation::init(conf);
}
colvar::orientation::~orientation() {}
int colvar::orientation::init(std::string const &conf)
{
int error_code = cvc::init(conf);
atoms = parse_group(conf, "atoms");
if (!atoms || atoms->size() == 0) {
return error_code | COLVARS_INPUT_ERROR;
}
ref_pos.reserve(atoms->size());
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());
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);
}
}
if (error_code != COLVARS_OK) return error_code;
if (!ref_pos.size()) {
return cvm::error("Error: must define a set of "
"reference coordinates.\n", COLVARS_INPUT_ERROR);
}
cvm::rvector ref_cog(0.0, 0.0, 0.0);
size_t 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));
// initialize rot member data
if (!atoms->noforce) {
rot.request_group2_gradients(atoms->size());
}
// If the debug gradients feature is active, debug the rotation gradients
// (note that this won't be active for the orientation CVC itself, because
// colvardeps prevents the flag's activation)
rot.b_debug_gradients = is_enabled(f_cvc_debug_gradient);
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()
{
rot.b_debug_gradients = is_enabled(f_cvc_debug_gradient);
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) {
x.quaternion_value = rot.q;
@ -131,9 +135,12 @@ void colvar::orientation::apply_force(colvarvalue const &force)
cvm::quaternion const &FQ = force.quaternion_value;
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++) {
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
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");
init_as_angle();
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();
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) {
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))) :
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++) {
(*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)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
cvc::apply_force(force);
}
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)
: orientation()
colvar::orientation_proj::orientation_proj()
{
set_function_type("orientationProj");
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
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()
{
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;
}
@ -246,42 +262,28 @@ void colvar::orientation_proj::calc_value()
void colvar::orientation_proj::calc_gradients()
{
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++) {
(*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) {
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(orientation_proj)
colvar::tilt::tilt(std::string const &conf)
: orientation()
colvar::tilt::tilt()
{
set_function_type("tilt");
x.type(colvarvalue::type_scalar);
enable(f_cvc_explicit_gradient);
init_scalar_boundaries(-1.0, 1.0);
tilt::init(conf);
}
int colvar::tilt::init(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= orientation::init(conf);
int error_code = orientation_proj::init(conf);
get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
if (axis.norm2() != 1.0) {
@ -297,7 +299,8 @@ void colvar::tilt::calc_value()
{
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);
}
@ -307,64 +310,24 @@ void colvar::tilt::calc_gradients()
{
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++) {
(*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++) {
(*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) {
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(tilt)
colvar::spin_angle::spin_angle(std::string const &conf)
: orientation()
{
set_function_type("spinAngle");
init_as_periodic_angle();
enable(f_cvc_periodic);
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);
init_as_periodic_angle();
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();
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);
this->wrap(x);
wrap(x);
}
@ -383,80 +347,20 @@ void colvar::spin_angle::calc_gradients()
{
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++) {
(*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++) {
(*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()
: orientation()
{
set_function_type("eulerPhi");
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()
{
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& 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 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;
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++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) +
(dxdq1 * (rot.dQ0_2[ia])[1]) +
(dxdq2 * (rot.dQ0_2[ia])[2]) +
(dxdq3 * (rot.dQ0_2[ia])[3]);
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(*atoms)[ia].grad = (dxdq0 * dq0_2[0]) +
(dxdq1 * dq0_2[1]) +
(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()
: orientation()
{
set_function_type("eulerPsi");
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()
{
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& 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 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;
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++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) +
(dxdq1 * (rot.dQ0_2[ia])[1]) +
(dxdq2 * (rot.dQ0_2[ia])[2]) +
(dxdq3 * (rot.dQ0_2[ia])[3]);
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(*atoms)[ia].grad = (dxdq0 * dq0_2[0]) +
(dxdq1 * dq0_2[1]) +
(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()
: orientation()
{
set_function_type("eulerTheta");
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()
{
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& 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 dxdq2 = (180.0/PI) * 2 * q0 / 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++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) +
(dxdq1 * (rot.dQ0_2[ia])[1]) +
(dxdq2 * (rot.dQ0_2[ia])[2]) +
(dxdq3 * (rot.dQ0_2[ia])[3]);
rot_deriv_impl->calc_derivative_wrt_group2(ia, nullptr, &dq0_2);
(*atoms)[ia].grad = (dxdq0 * dq0_2[0]) +
(dxdq1 * dq0_2[1]) +
(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 "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
colvar::map_total::map_total()
: cvc()
{
set_function_type("mapTotal");
volmap_id = -1;
volmap_index = -1;
atoms = NULL;
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 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)) {
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
atoms = parse_group(conf, "atoms", true);
if (atoms != NULL) {
if (atoms) {
// Using internal selection
if (volmap_name.size()) {
@ -74,11 +57,11 @@ int colvar::map_total::init(std::string const &conf)
if (volmap_id >= 0) {
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 (atoms == NULL) {
if (!atoms) {
error_code |= cvm::error("Error: weights can only be assigned when atoms "
"are selected explicitly in Colvars.\n",
COLVARS_INPUT_ERROR);
@ -133,11 +116,10 @@ void colvar::map_total::calc_gradients()
void colvar::map_total::apply_force(colvarvalue const &force)
{
colvarproxy *proxy = cvm::main()->proxy;
if (atoms) {
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
cvc::apply_force(force);
} else {
colvarproxy *proxy = cvm::main()->proxy;
proxy->apply_volmap_force(volmap_index, force.real_value);
}
}

View File

@ -129,6 +129,11 @@ int colvardeps::enable(int feature_id,
int res;
size_t i, j;
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_state *fs = &feature_states[feature_id];

View File

@ -253,6 +253,8 @@ public:
f_cvb_write_ti_pmf,
/// \brief whether this bias uses an external grid to scale the biasing forces
f_cvb_scale_biasing_force,
/// \brief whether this bias is applied to one or more ext-Lagrangian colvars
f_cvb_extended,
f_cvb_ntot
};
@ -355,6 +357,8 @@ public:
f_cvc_lower_boundary,
/// This CVC provides a default value for the colvar's 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
f_cvc_gradient,
/// CVC calculates and stores explicit atom gradients on rank 0

View File

@ -8,13 +8,11 @@
// Colvars repository at GitHub.
#include <ctime>
#include <fstream>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
#include "colvargrid.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)
{}
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)
{
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)
{
return colvar_grid<cvm::real>::read_multicol(is, add);
@ -195,30 +297,63 @@ cvm::real colvar_grid_scalar::entropy() const
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<cvm::real>(),
samples(NULL),
weights(NULL)
: colvar_grid<cvm::real>(), samples(NULL), full_samples(0), min_samples(0)
{}
colvar_grid_gradient::colvar_grid_gradient(std::vector<int> const &nx_i)
: colvar_grid<cvm::real>(nx_i, 0.0, nx_i.size()),
samples(NULL),
weights(NULL)
: colvar_grid<cvm::real>(nx_i, 0.0, nx_i.size()), samples(NULL), full_samples(0), min_samples(0)
{}
colvar_grid_gradient::colvar_grid_gradient(std::vector<colvar *> &colvars)
: colvar_grid<cvm::real>(colvars, 0.0, colvars.size()),
samples(NULL),
weights(NULL)
: colvar_grid<cvm::real>(colvars, 0.0, colvars.size()), samples(NULL), full_samples(0), min_samples(0)
{}
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<cvm::real>(),
samples(NULL),
weights(NULL)
samples(NULL)
{
std::istream &is = cvm::main()->proxy->input_stream(filename,
"gradient file");
@ -280,6 +415,57 @@ colvar_grid_gradient::colvar_grid_gradient(std::string &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)
{
@ -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),
b_smoothed(false),
gradients(gradients)
{
// 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)
: gradients(gradients)
integrate_potential::integrate_potential(std::shared_ptr<colvar_grid_gradient> gradients)
: b_smoothed(false),
gradients(gradients)
{
nd = gradients->num_variables();
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;
@ -438,22 +654,24 @@ int integrate_potential::integrate(const int itmax, const cvm::real &tol, cvm::r
} else {
corr = 0.0;
}
std::vector<int> ix;
// Iterate over valid indices in gradient grid
for (ix = new_index(); gradients->index_ok(ix); incr(ix)) {
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)) {
// 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);
}
} else if (nd <= 3) {
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 {
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);
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) {
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)
{
size_t count, i;
bool edge = gradients->wrap_edge(ix); // Detect edge if non-PBC
size_t i;
bool edge = gradients->wrap_detect_edge(ix); // Detect edge if non-PBC
if (gradients->samples) {
count = gradients->samples->value(ix);
} else {
count = 1;
}
if (!edge && count) {
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 {
if (edge) {
for ( i = 0; i<nd; i++ ) {
g[i] = 0.0;
}
return;
}
gradients->vector_value_smoothed(ix, g, b_smoothed);
}
void integrate_potential::update_div_local(const std::vector<int> &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 "colvar.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>
@ -90,6 +317,9 @@ std::istream & colvar_grid<T>::read_multicol(std::istream &is, bool add)
for (size_t i = 0; i < nd; i++ ) {
if ( !(is >> x) ) end_of_file = true;
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;

View File

@ -7,13 +7,10 @@
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <cstring>
#include <iostream>
#include <memory>
#include <vector>
#include <map>
#include "colvarmodule.h"
#include "colvarparse.h"
@ -21,6 +18,7 @@
#include "colvar.h"
#include "colvarbias.h"
#include "colvarbias_abf.h"
#include "colvarbias_abmd.h"
#include "colvarbias_alb.h"
#include "colvarbias_histogram.h"
#include "colvarbias_histogram_reweight_amd.h"
@ -29,7 +27,7 @@
#include "colvarscript.h"
#include "colvaratoms.h"
#include "colvarcomp.h"
#include "colvars_memstream.h"
/// Track usage of Colvars features
@ -69,6 +67,11 @@ protected:
};
namespace {
constexpr uint32_t colvars_magic_number = 2013813594;
}
colvarmodule::colvarmodule(colvarproxy *proxy_in)
{
depth_s = 0;
@ -98,16 +101,14 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
version_int = proxy->get_version_from_string(COLVARS_VERSION);
cvm::log(cvm::line_marker);
cvm::log("Initializing the collective variables module, version "+
version()+".\n");
cvm::log(
"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"
" https://doi.org/10.1080/00268976.2013.813594\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)
cvm::log("This version was built with the C++11 standard or higher.\n");
#else
@ -116,8 +117,38 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
" https://colvars.github.io/README-c++11.html\n");
#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
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" should be updated by the proxy
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)
{
cvm::log(cvm::line_marker);
@ -327,6 +365,7 @@ void colvarmodule::config_changed()
int colvarmodule::parse_global_params(std::string const &conf)
{
int error_code = COLVARS_OK;
// TODO document and then echo this keyword
parse->get_keyval(conf, "logLevel", log_level_, log_level_,
colvarparse::parse_silent);
@ -334,10 +373,7 @@ int colvarmodule::parse_global_params(std::string const &conf)
std::string units;
if (parse->get_keyval(conf, "units", units)) {
units = colvarparse::to_lower_cppstr(units);
int error_code = proxy->set_unit_system(units, (colvars.size() != 0));
if (error_code != COLVARS_OK) {
return error_code;
}
error_code |= proxy->set_unit_system(units, (colvars.size() != 0));
}
}
@ -346,7 +382,7 @@ int colvarmodule::parse_global_params(std::string const &conf)
size_t pos = 0;
while (parse->key_lookup(conf, "indexFile", &index_file_name, &pos)) {
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();
}
}
@ -358,9 +394,8 @@ int colvarmodule::parse_global_params(std::string const &conf)
}
bool b_analysis = true;
if (parse->get_keyval(conf, "analysis", b_analysis, true,
colvarparse::parse_silent)) {
cvm::log("Warning: keyword \"analysis\" is deprecated: it is now set "
if (parse->get_keyval(conf, "analysis", b_analysis, true, colvarparse::parse_silent)) {
cvm::log("Warning: keyword \"analysis\" is deprecated: it is now always set "
"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);
#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
parse_biases_type<colvarbias_abf>(conf, "abf");
/// initialize ABMD instances
parse_biases_type<colvarbias_abmd>(conf, "abmd");
/// initialize adaptive linear biases
parse_biases_type<colvarbias_alb>(conf, "ALB");
@ -791,29 +834,27 @@ int colvarmodule::calc()
// write restart files and similar data
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()) {
// Write restart file, if different from main output
error_code |= write_restart_file(restart_out_name);
} else {
error_code |= write_restart_file(output_prefix()+".colvars.state");
} else if (output_prefix().size()) {
error_code |= write_restart_file(output_prefix() + ".colvars.state");
}
if (output_prefix().size()) {
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
for (std::vector<colvar *>::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) {
// TODO remove this when corrFunc becomes a bias
error_code |= (*cvi)->write_output_files();
}
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
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
cvm::increase_depth();
@ -881,7 +922,7 @@ int colvarmodule::calc_colvars()
}
// 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
@ -963,8 +1004,16 @@ int colvarmodule::calc_biases()
}
}
// if SMP support is available, split up the work
if (proxy->smp_enabled() == COLVARS_OK) {
bool biases_need_main_thread = false;
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) {
// calculate biases and scripted forces in parallel
@ -980,10 +1029,12 @@ int colvarmodule::calc_biases()
error_code |= calc_scripted_forces();
}
// Straight loop over biases on a single thread
cvm::increase_depth();
for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
error_code |= (*bi)->update();
if (cvm::get_error()) {
cvm::decrease_depth();
return error_code;
}
}
@ -994,7 +1045,7 @@ int colvarmodule::calc_biases()
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");
std::ostream &restart_out_os = proxy->output_stream(out_name, "state file");
if (!restart_out_os) return COLVARS_FILE_ERROR;
if (!write_restart(restart_out_os)) {
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);
// 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");
std::ostringstream os;
if (!write_restart(os)) {
if (!write_state(os)) {
return cvm::error("Error: in writing restart to buffer.\n", COLVARS_FILE_ERROR);
}
output = os.str();
@ -1207,9 +1271,17 @@ int colvarmodule::end_of_step()
int colvarmodule::update_engine_parameters()
{
if (this->size() == 0) return cvm::get_error();
for (std::vector<colvar *>::iterator cvi = variables()->begin();
cvi != variables()->end(); cvi++) {
if (size() == 0) {
// No-op if no variables or biases are defined
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();
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
@ -1250,10 +1322,10 @@ int colvarmodule::reset()
parse->clear();
// Iterate backwards because we are deleting the elements as we go
for (std::vector<colvarbias *>::reverse_iterator bi = biases.rbegin();
bi != biases.rend();
bi++) {
delete *bi; // the bias destructor updates the biases array
while (!biases.empty()) {
colvarbias* tail = biases.back();
biases.pop_back();
delete tail; // the bias destructor updates the biases array
}
biases.clear();
biases_active_.clear();
@ -1262,11 +1334,11 @@ int colvarmodule::reset()
reinterpret_cast<std::map<std::string, int> *>(num_biases_types_used_)->clear();
// Iterate backwards because we are deleting the elements as we go
for (std::vector<colvar *>::reverse_iterator cvi = colvars.rbegin();
cvi != colvars.rend();
cvi++) {
delete *cvi; // the colvar destructor updates the colvars array
}
while (!colvars.empty()) {
colvar* cvi = colvars.back();
colvars.pop_back();
delete cvi; // the colvar destructor updates the colvars array
};
colvars.clear();
reset_index_groups();
@ -1274,64 +1346,119 @@ int colvarmodule::reset()
proxy->flush_output_streams();
proxy->reset();
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
clear_error();
return COLVARS_OK;
}
int colvarmodule::setup_input()
{
if (proxy->input_prefix().size()) {
// Read a state 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 (proxy->input_prefix().empty() && (!proxy->input_stream_exists("input state string")) &&
input_state_buffer_.empty()) {
// If no input sources have been defined up to this point, use defaultInputStateFile
proxy->set_input_prefix(default_input_state_file_);
}
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) {
// Try without the suffix ".colvars.state"
restart_in_name = proxy->input_prefix();
input_is = &(proxy->input_stream(restart_in_name,
"restart file/channel"));
input_is = &(proxy->input_stream(restart_in_name, "restart file/channel"));
if (!*input_is) {
// Error message has already been printed, return now
return COLVARS_FILE_ERROR;
}
}
// Now that the file has been opened, clear this field so that this
// function will not be called twice
proxy->input_prefix().clear();
// Now that the file has been opened, clear this field so that this block
// will not be executed twice
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);
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;
uint32_t file_magic_number = 0;
if (file_size > sizeof(uint32_t)) {
if (input_is->read(reinterpret_cast<char *>(&file_magic_number), sizeof(uint32_t))) {
if (file_magic_number == colvars_magic_number) {
binary_state_file = true;
}
// TODO This could soon be redundant
if (proxy->input_buffer() != NULL) {
// Read a string buffer
char const *buffer = proxy->input_buffer();
size_t const buffer_size = strlen(proxy->input_buffer());
// Clear proxy pointer for the next round
proxy->input_buffer() = NULL;
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();
input_is->seekg(0, std::ios::beg);
}
}
return COLVARS_OK;
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);
}
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("");
std::string const state_file_format(binary_restart ? " (binary format)" : "");
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");
}
if (output_prefix() != proxy->output_prefix()) {
output_prefix() = proxy->output_prefix();
if (output_prefix().size()) {
cvm::log("The final output state file will be \""+
(output_prefix().size() ?
std::string(output_prefix()+".colvars.state") :
std::string("colvars.state"))+"\".\n");
// cvm::log (cvm::line_marker);
cvm::log("The final output state file will be \"" +
(output_prefix().size() ? std::string(output_prefix() + ".colvars.state")
: std::string("colvars.state")) +
"\".\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(""));
(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();
return error_code;
}
@ -1390,8 +1520,7 @@ std::string colvarmodule::state_file_prefix(char const *filename)
}
std::istream & colvarmodule::read_restart(std::istream &is)
template <typename IST> IST & colvarmodule::read_state_template_(IST &is)
{
bool warn_total_forces = false;
@ -1417,8 +1546,11 @@ std::istream & colvarmodule::read_restart(std::istream &is)
}
if (restart_version() != version()) {
cvm::log("This state file was generated with version "+
restart_version()+"\n");
cvm::log("This state file was generated with version " + 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) {
@ -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::streampos pos = 0;
auto pos = is.tellg();
std::string word;
while (is.good()) {
while (is) {
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") {
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
if ( !((*cvi)->read_state(is)) ) {
for (std::vector<colvar *>::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) {
if (!((*cvi)->read_state(is))) {
// Here an error signals that the variable is a match, but the
// state is corrupt; otherwise, the variable rewinds is silently
cvm::error("Error: in reading restart configuration for "
"collective variable \""+(*cvi)->name+"\".\n",
cvm::error("Error: in reading state for collective variable \"" +
(*cvi)->name + "\" at position " + cvm::to_str(is.tellg()) +
" in stream.\n",
COLVARS_INPUT_ERROR);
}
if (is.tellg() > pos) break; // found it
if (is.tellg() > pos)
break; // found it
}
cvm::decrease_depth();
@ -1498,11 +1668,12 @@ std::istream & colvarmodule::read_objects_state(std::istream &is)
}
if (!((*bi)->read_state(is))) {
// Same as above, an error means a match but the state is incorrect
cvm::error("Error: in reading restart configuration for bias \""+
(*bi)->name+"\".\n",
cvm::error("Error: in reading state for bias \"" + (*bi)->name + "\" at position " +
cvm::to_str(is.tellg()) + " in stream.\n",
COLVARS_INPUT_ERROR);
}
if (is.tellg() > pos) break; // found it
if (is.tellg() > pos)
break; // found it
}
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)
{
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);
os << "configuration {\n"
<< " step " << std::setw(it_width)
bool const formatted = !std::is_same<OST, cvm::memory_stream>::value;
std::ostringstream oss;
oss.setf(std::ios::scientific, std::ios::floatfield);
oss << " step " << std::setw(it_width)
<< it << "\n"
<< " dt " << dt() << "\n"
<< " version " << std::string(COLVARS_VERSION) << "\n";
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;
@ -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);
@ -1765,7 +1986,7 @@ size_t & colvarmodule::depth()
{
// NOTE: do not call log() or error() here, to avoid recursion
colvarmodule *cv = cvm::main();
if (proxy->smp_enabled() == COLVARS_OK) {
if (proxy->check_smp_enabled() == COLVARS_OK) {
int const nt = proxy->smp_num_threads();
if (int(cv->depth_v.size()) != nt) {
proxy->smp_lock();
@ -1810,7 +2031,7 @@ void colvarmodule::clear_error()
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) ?
(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,
std::vector<cvm::rvector> *pos,
cvm::atom_group *atoms,
@ -1953,7 +2165,7 @@ int cvm::load_coords(char const *file_name,
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
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);
} else {
// Otherwise, call proxy function for PDB
error_code |= proxy->load_coords(file_name,
sorted_pos, atoms->sorted_ids(),
pdb_field, pdb_field_value);
error_code |= proxy->load_coords_pdb(file_name, sorted_pos, atoms->sorted_ids(), pdb_field,
pdb_field_value);
}
if (error_code != COLVARS_OK) return error_code;
std::vector<int> const &map = atoms->sorted_ids_map();
for (size_t i = 0; i < atoms->size(); i++) {
(*pos)[map[i]] = sorted_pos[i];
@ -1985,7 +2198,7 @@ int cvm::load_coords_xyz(char const *filename,
bool keep_open)
{
std::istream &xyz_is = proxy->input_stream(filename, "XYZ file");
unsigned int natoms;
size_t natoms;
char symbol[256];
std::string line;
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);
xyz_is.width(255);
} else {
proxy->close_input_stream(filename);
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();
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
if (!atoms) {
// 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",
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();
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);
xyz_natoms++;
} else {
proxy->close_input_stream(filename);
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);
xyz_natoms++;
} else {
proxy->close_input_stream(filename);
return cvm::error(error_msg, COLVARS_INPUT_ERROR);
}
}
}
if (xyz_natoms != pos->size()) {
proxy->close_input_stream(filename);
return cvm::error("Error: The number of positions read from file \""+
std::string(filename)+"\" does not match the number of "+
"positions required: "+cvm::to_str(xyz_natoms)+" vs. "+

View File

@ -10,7 +10,7 @@
#ifndef COLVARMODULE_H
#define COLVARMODULE_H
#include <cmath>
#include <cstdint>
#include "colvars_version.h"
@ -19,9 +19,11 @@
#endif
/*! \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.
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
@ -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
/// objects.
#define COLVARS_OK 0
#define COLVARS_ERROR 1
#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 <cmath>
#include <iosfwd>
#include <string>
#include <vector>
#include <list>
#include <iosfwd>
class colvarparse;
class colvar;
class colvarbias;
class colvarproxy;
class colvarscript;
class colvarvalue;
@ -67,14 +58,6 @@ class colvarvalue;
/// child objects
class colvarmodule {
private:
/// Impossible to initialize the main object without arguments
colvarmodule();
/// Integer representing the version string (allows comparisons)
int version_int;
public:
/// Get the version string (YYYY-MM-DD format)
@ -89,9 +72,21 @@ public:
return version_int;
}
friend class colvarproxy;
// TODO colvarscript should be unaware of colvarmodule's internals
friend class colvarscript;
/// Get the patch version number (non-zero in patch releases of other packages)
int patch_version_number() const
{
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
typedef long long step_number;
@ -190,7 +185,9 @@ public:
template <class T> class matrix2d;
class quaternion;
class rotation;
class usage;
class memory_stream;
/// Residue identifier
typedef int residue_id;
@ -205,8 +202,6 @@ public:
// allow these classes to access protected data
class atom;
class atom_group;
friend class atom;
friend class atom_group;
typedef std::vector<atom>::iterator atom_iter;
typedef std::vector<atom>::const_iterator atom_const_iter;
@ -247,6 +242,8 @@ public:
return it;
}
bool binary_restart;
/// \brief Finite difference step size (if there is no dynamics, or
/// if gradients need to be tested independently from the size of
/// dt)
@ -342,9 +339,19 @@ public:
/// \param Pointer to instance of the proxy class (communicate with engine)
colvarmodule(colvarproxy *proxy);
private:
/// Cannot initialize the main object without a proxy
colvarmodule();
public:
/// Destructor
~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
int reset();
@ -449,17 +456,52 @@ public:
/// (Re)initialize the output trajectory and state file (does not write it yet)
int setup_output();
/// Read a restart file
std::istream & read_restart(std::istream &is);
private:
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
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
int print_total_forces_errning(bool warn_total_forces);
/// Write the output restart file
std::ostream & write_restart(std::ostream &os);
private:
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
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);
/// 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:
@ -715,17 +757,6 @@ public:
/// Clear the index groups loaded so far
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);
/// 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
@ -755,7 +786,7 @@ public:
std::string restart_out_name;
/// Pseudo-random number with Gaussian distribution
static real rand_gaussian(void);
static real rand_gaussian();
protected:
@ -838,9 +869,20 @@ public:
typedef colvarmodule cvm;
std::ostream & operator << (std::ostream &os, cvm::rvector const &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

View File

@ -14,6 +14,22 @@
" url = {https://doi.org/10.1016/j.softx.2015.06.001}\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_url_[std::string("Chen2021")] = "https://doi.org/10.1021/acs.jctc.1c00103";
paper_bibtex_[std::string("Chen2021")] =
@ -182,6 +198,19 @@
" url = {https://doi.org/10.1021/ct9004432}\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_url_[std::string("Humphrey1996")] = "https://doi.org/10.1016/0263-7855(96)00018-5";
paper_bibtex_[std::string("Humphrey1996")] =
@ -215,19 +244,6 @@
" url = {https://doi.org/10.1021/acs.jpcb.6b10055}\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_url_[std::string("Marinelli2015")] = "https://doi.org/10.1016/j.bpj.2015.05.024";
paper_bibtex_[std::string("Marinelli2015")] =
@ -335,6 +351,9 @@
feature_count_[std::string("GROMACS engine")] = 0;
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_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_paper_map_[std::string("orientationAngle colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("orientationProj colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("orientationProj colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("orientationProj colvar component (derived from orientationAngle)")] = 0;
feature_paper_map_[std::string("orientationProj colvar component (derived from orientationAngle)")] = "Fiorin2013";
feature_count_[std::string("spinAngle colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("spinAngle colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("spinAngle colvar component (derived from tilt)")] = 0;
feature_paper_map_[std::string("spinAngle colvar component (derived from tilt)")] = "Fiorin2013";
feature_count_[std::string("tilt colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("tilt colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("tilt colvar component (derived from orientationProj)")] = 0;
feature_paper_map_[std::string("tilt colvar component (derived from orientationProj)")] = "Fiorin2013";
feature_count_[std::string("alpha colvar component")] = 0;
feature_paper_map_[std::string("alpha colvar component")] = "Fiorin2013";
@ -479,14 +498,14 @@
feature_count_[std::string("polarPhi colvar component")] = 0;
feature_paper_map_[std::string("polarPhi colvar component")] = "Fu2017";
feature_count_[std::string("eulerPhi colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("eulerPhi colvar component (derived from orientation)")] = "Fu2017";
feature_count_[std::string("eulerPhi colvar component (derived from orientation_angle)")] = 0;
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_paper_map_[std::string("eulerTheta colvar component (derived from orientation)")] = "Fu2017";
feature_count_[std::string("eulerTheta colvar component (derived from orientation_angle)")] = 0;
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_paper_map_[std::string("eulerPsi colvar component (derived from orientation)")] = "Fu2017";
feature_count_[std::string("eulerPsi colvar component (derived from orientation_angle)")] = 0;
feature_paper_map_[std::string("eulerPsi colvar component (derived from orientation_angle)")] = "Fu2017";
feature_count_[std::string("dipoleAngle colvar component")] = 0;
feature_paper_map_[std::string("dipoleAngle colvar component")] = "Garate2019";
@ -500,6 +519,9 @@
feature_count_[std::string("Internal-forces free energy estimator")] = 0;
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_paper_map_[std::string("VMD engine")] = "Humphrey1996";
@ -509,9 +531,6 @@
feature_count_[std::string("CZAR eABF estimator")] = 0;
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_paper_map_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = "Marinelli2015";
@ -539,9 +558,6 @@
feature_count_[std::string("Colvars-GROMACS interface")] = 0;
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_paper_map_[std::string("gspath colvar component")] = "n/a";
@ -571,3 +587,6 @@
feature_count_[std::string("Scripted functions (Tcl)")] = 0;
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.
#include <sstream>
#include <iostream>
#include <algorithm>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvars_memstream.h"
// 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)
{
bool b_found = false, b_found_any = false;
size_t save_pos = 0, found_count = 0;
size_t save_pos = 0;
data.clear();
@ -110,7 +110,6 @@ bool colvarparse::get_key_string_multi_value(std::string const &conf,
if (b_found) {
if (!b_found_any)
b_found_any = true;
found_count++;
data.push_back(data_this);
}
} 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 (brace_count == 0) {
data_end = brace+1;
break;
}
brace = line.find_first_of("{}", brace+1);
}
if (brace_count == 0) {
data_end = brace+1;
break;
}
@ -869,55 +866,107 @@ colvarparse::read_block::~read_block()
std::istream & operator>> (std::istream &is, colvarparse::read_block const &rb)
{
std::streampos start_pos = is.tellg();
std::string read_key, next;
auto start_pos = is.tellg();
if ( !(is >> read_key) || !(read_key == rb.key) ||
!(is >> next) ) {
// the requested keyword has not been found, or it is not possible
// to read data after it
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, std::ios::beg);
is.seekg(start_pos);
is.setstate(std::ios::failbit);
return is;
}
if (next != "{") {
std::string next;
if (is >> 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;
while (colvarparse::getline_nocomments(is, line)) {
size_t br = 0, br_old = 0;
while ( (br = line.find_first_of("{}", br)) != std::string::npos) {
if (line[br] == '{') brace_count++;
if (line[br] == '}') brace_count--;
while ((br = line.find_first_of("{}", br)) != std::string::npos) {
if (line[br] == '{')
brace_count++;
if (line[br] == '}')
brace_count--;
br_old = br;
br++;
}
if (brace_count) {
if (rb.data) {
(rb.data)->append(line + "\n");
if (brace_count || block_only) {
// Add whole line if (1) brace are unmatched or (2) we're reading the whole stream anyway
if (data) {
data->append(line + "\n");
}
}
else {
if (rb.data) {
(rb.data)->append(line, 0, br_old);
} else {
// Not reading whole block and braces are matched; add until before the last brace
if (data) {
data->append(line.substr(0, br_old) + "\n");
}
break;
}
}
if (brace_count) {
// end-of-file reached
// restore initial position
if (block_only) {
if (is.rdstate() & std::ios::eofbit) {
// Clear EOF errors if we were meant to read the whole block
is.clear();
is.seekg(start_pos, std::ios::beg);
}
} 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;
}

View File

@ -11,6 +11,7 @@
#define COLVARPARSE_H
#include <cstring>
#include <list>
#include <string>
#include "colvarmodule.h"
@ -40,7 +41,7 @@ public:
void set_string(std::string const &conf);
/// Default destructor
virtual ~colvarparse();
~colvarparse() override;
/// Get the configuration string (includes comments)
inline std::string const & get_config() const
@ -109,12 +110,12 @@ public:
bool get_keyval(std::string const &conf,
char const *key,
int &value,
int const &def_value = (int)0,
int const &def_value = 0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
size_t &value,
size_t const &def_value = (size_t)0,
size_t const &def_value = 0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
@ -134,7 +135,7 @@ public:
bool get_keyval(std::string const &conf,
char const *key,
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);
bool get_keyval(std::string const &conf,
char const *key,
@ -159,17 +160,17 @@ public:
bool get_keyval(std::string const &conf,
char const *key,
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);
bool get_keyval(std::string const &conf,
char const *key,
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);
bool get_keyval(std::string const &conf,
char const *key,
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);
bool get_keyval(std::string const &conf,
char const *key,
@ -179,7 +180,7 @@ public:
bool get_keyval(std::string const &conf,
char const *key,
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);
bool get_keyval(std::string const &conf,
char const *key,
@ -262,33 +263,41 @@ public:
{
std::string out = "";
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;
}
/// \brief Helper class to read a block of the type "key { ... }"
/// from a stream and store it in a string
/// Helper class to read a block "key { ... }" from a stream and store it in a string
///
/// Useful on restarts, where the file is too big to be loaded in a
/// string by key_lookup; it can only check that the keyword is
/// correct and the block is properly delimited by braces, not
/// skipping other blocks
/// Useful on restarts, where the file is too big to be loaded in a string
/// by key_lookup(); it can only check that the keyword is correct and the
/// block is properly delimited by braces, not skipping other blocks
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:
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 from stream, first check that key matches, then call read_contents()
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
bool key_lookup(std::string const &conf,
char const *key,
std::string *data = NULL,
size_t *save_pos = NULL);
std::string *data = nullptr,
size_t *save_pos = nullptr);
/// \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

View File

@ -13,8 +13,9 @@
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvar.h"
#include "colvarbias.h"
#include "colvarscript.h"
#include "colvaratoms.h"
#include "colvarmodule_utils.h"
@ -23,6 +24,7 @@ colvarproxy_atoms::colvarproxy_atoms()
{
atoms_rms_applied_force_ = atoms_max_applied_force_ = 0.0;
atoms_max_applied_force_id_ = -1;
modified_atom_list_ = 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_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));
modified_atom_list_ = true;
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 */,
std::string const & /* atom_name */,
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()
{
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 (b_smp_active) {
@ -299,7 +285,7 @@ int colvarproxy_smp::smp_colvars_loop()
colvarmodule *cv = cvm::main();
colvarproxy *proxy = cv->proxy;
#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];
int x_item = (*(cv->variables_active_smp_items()))[i];
if (cvm::debug()) {
@ -324,7 +310,7 @@ int colvarproxy_smp::smp_biases_loop()
#pragma omp parallel
{
#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];
if (cvm::debug()) {
cvm::log("Calculating bias \""+b->name+"\" on thread "+
@ -351,7 +337,7 @@ int colvarproxy_smp::smp_biases_script_loop()
cv->calc_scripted_forces();
}
#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];
if (cvm::debug()) {
cvm::log("Calculating bias \""+b->name+"\" on thread "+
@ -484,16 +470,21 @@ colvarproxy::~colvarproxy()
bool colvarproxy::io_available()
{
return (smp_enabled() == COLVARS_OK && smp_thread_id() == 0) ||
(smp_enabled() != COLVARS_OK);
return (check_smp_enabled() == COLVARS_OK && smp_thread_id() == 0) ||
(check_smp_enabled() != COLVARS_OK);
}
int colvarproxy::reset()
{
if (cvm::debug()) {
cvm::log("colvarproxy::reset()\n");
}
int error_code = COLVARS_OK;
error_code |= colvarproxy_atoms::reset();
error_code |= colvarproxy_atom_groups::reset();
error_code |= colvarproxy_volmaps::reset();
total_force_requested = false;
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()
{
return COLVARS_OK;
@ -591,47 +607,78 @@ void colvarproxy::print_input_atomic_data()
cvm::log(cvm::line_marker);
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())+", "+
"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())+", "+
"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())+", "+
"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())+", "+
"atoms_positions = "+cvm::to_str(atoms_positions,
"atoms_positions[size = "+cvm::to_str(atoms_positions.size())+
"] = "+cvm::to_str(atoms_positions,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_total_forces = "+cvm::to_str(atoms_total_forces,
"atoms_total_forces[size = "+
cvm::to_str(atoms_total_forces.size())+
"] = "+cvm::to_str(atoms_total_forces,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log(cvm::line_marker);
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())+", "+
"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())+", "+
"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())+", "+
"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())+", "+
"atom_groups_coms = "+cvm::to_str(atom_groups_coms,
"atom_groups_coms[size = "+
cvm::to_str(atom_groups_coms.size())+
"] = "+cvm::to_str(atom_groups_coms,
cvm::cv_width,
cvm::cv_prec)+"\n");
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::to_str(atom_groups_total_forces.size())+
"] = "+cvm::to_str(atom_groups_total_forces,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log(cvm::line_marker);
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())+", "+
"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);
}

View File

@ -12,7 +12,6 @@
#include "colvarmodule.h"
#include "colvartypes.h"
#include "colvarvalue.h"
#include "colvarproxy_io.h"
#include "colvarproxy_system.h"
#include "colvarproxy_tcl.h"
@ -56,6 +55,9 @@ public:
/// corresponding atom yet
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
/// residue number. Not all programs support this: leave this function as
/// is in those cases.
@ -72,31 +74,6 @@ public:
/// (costly) set the corresponding atoms_refcount to zero
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
int reset();
@ -245,6 +222,18 @@ public:
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
inline bool updated_masses() const
{
@ -284,6 +273,9 @@ protected:
/// ID of the atom with the maximum norm among all applied forces
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
bool updated_masses_, updated_charges_;
@ -466,7 +458,7 @@ public:
bool b_smp_active;
/// 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
virtual int smp_colvars_loop();
@ -565,9 +557,9 @@ public:
/// \brief Interface between the collective variables module and
/// the simulation or analysis program (NAMD, VMD, LAMMPS...).
/// This is the base class: each interfaced program is supported by a derived class.
/// Interface between Colvars and MD engine (GROMACS, LAMMPS, NAMD, VMD...)
///
/// This is the base class: each engine is supported by a derived class.
class colvarproxy
: public colvarproxy_system,
public colvarproxy_atoms,
@ -589,15 +581,20 @@ public:
colvarproxy();
/// 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)
virtual int request_deletion();
/// Whether deallocation was requested
inline bool delete_requested()
inline bool delete_requested() const
{
return b_delete_requested;
}
@ -608,6 +605,26 @@ public:
/// (Re)initialize the module
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)
virtual int setup();
@ -703,7 +720,10 @@ protected:
/// Track which features have been acknowledged during the last run
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
void *config_queue_;

View File

@ -29,7 +29,6 @@
colvarproxy_io::colvarproxy_io()
{
input_buffer_ = NULL;
restart_frequency_engine = 0;
input_stream_error_ = new std::istringstream();
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;
#if defined(_WIN32) && !defined(__CYGWIN__)
// On straight Windows, must remove the destination before renaming it
if (_access(newfilename, 00) == 0) {
error_code |= remove_file(newfilename);
}
#endif
int rename_exit_code = 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::string const description,
bool error_on_fail)
@ -162,13 +208,18 @@ std::istream &colvarproxy_io::input_stream(std::string const &input_name,
}
if (colvarproxy_io::input_stream_exists(input_name)) {
return *(input_streams_[input_name]);
}
// Using binary to work around differences in line termination conventions
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);
}
if (input_streams_[input_name]->fail() && error_on_fail) {
cvm::error("Error: cannot open "+description+" \""+input_name+"\".\n",
@ -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)
{
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)
{
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);
return COLVARS_OK;
}
@ -199,7 +316,8 @@ int colvarproxy_io::close_input_stream(std::string const &input_name)
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++) {
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::string const description)
{
@ -228,7 +359,7 @@ std::ostream & colvarproxy_io::output_stream(std::string const &output_name,
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])) {
cvm::error("Error: cannot write to "+description+" \""+output_name+"\".\n",
COLVARS_FILE_ERROR);
@ -303,6 +434,7 @@ int colvarproxy_io::close_output_streams()
osi != output_streams_.end();
osi++) {
(dynamic_cast<std::ofstream *>(osi->second))->close();
delete osi->second;
}
output_streams_.clear();

View File

@ -10,9 +10,10 @@
#ifndef COLVARPROXY_IO_H
#define COLVARPROXY_IO_H
#include <iosfwd>
#include <list>
#include <map>
#include <string>
#include <iosfwd>
/// Methods for data input/output
@ -66,57 +67,80 @@ public:
}
/// 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;
}
/// 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)
inline std::string & output_prefix()
inline std::string const & output_prefix() const
{
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
inline std::string & restart_output_prefix()
inline std::string const & restart_output_prefix() const
{
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)
inline int default_restart_frequency() const
{
return restart_frequency_engine;
}
/// Buffer from which the input state information may be read
inline char const * & input_buffer()
{
return input_buffer_;
}
/// Communicate/set the restart frequency of the simulation engine
virtual int set_default_restart_frequency(int freq);
// 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
/// \param input_name File name (later only a handle)
/// \param description Purpose of the file
/// \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",
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)
virtual bool input_stream_exists(std::string const &input_name);
bool input_stream_exists(std::string const &input_name);
/// 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
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)
/// \param output_name File name or identifier
/// \param description Purpose of the file
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)
virtual bool output_stream_exists(std::string const &output_name);
@ -158,9 +182,6 @@ protected:
/// Object whose reference is returned when write errors occur
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;
kcal_mol_value_ = 0.0;
timestep_ = 1.0;
target_temperature_ = 0.0;
boltzmann_ = 0.001987191; // Default: kcal/mol/K
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
return 1.0;
timestep_ = dt;
return COLVARS_OK;
}

View File

@ -61,8 +61,14 @@ public:
/// Set the current target temperature of the simulation (K units)
virtual int set_target_temperature(cvm::real T);
/// \brief Time step of the simulation (fs)
virtual cvm::real dt();
/// Time step of the simulation (fs units)
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
virtual cvm::real rand_gaussian(void);
@ -137,9 +143,12 @@ protected:
/// Boltzmann constant in internal Colvars units
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_;
/// 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
/// * 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

View File

@ -83,7 +83,7 @@ int colvarproxy_tcl::tcl_run_file(std::string const &fileName)
Tcl_Interp *const interp = get_tcl_interp();
int err = Tcl_EvalFile(interp, fileName.c_str());
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));
return COLVARS_ERROR;
}

View File

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

View File

@ -18,8 +18,8 @@ public:
/// Clear volumetric map data
int reset();
/// \brief Whether this implementation has capability to use volumetric maps
virtual int volmaps_available();
/// Test whether this implementation can use volumetric maps as CVs
virtual int check_volmaps_available();
/// Create a slot for a volumetric map not requested yet
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
#define COLVARS_VERSION "2023-05-01"
#define COLVARS_VERSION "2024-06-04"
#endif

View File

@ -7,8 +7,6 @@
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <cstdlib>
#include <cstring>
#include <sstream>
#include "colvarproxy.h"
@ -35,6 +33,7 @@ colvarscript::colvarscript(colvarproxy *p, colvarmodule *m)
: proxy_(p),
colvars(m)
{
cmdline_main_cmd_ = std::string("cv");
cmd_names = NULL;
init_commands();
#ifdef COLVARS_TCL
@ -141,7 +140,7 @@ int colvarscript::init_command(colvarscript::command const &comm,
}
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] += "----------\n\n";
size_t i;
@ -281,11 +280,15 @@ std::string colvarscript::get_command_cmdline_syntax(colvarscript::Object_type t
switch (t) {
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:
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:
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:
// Already handled, but silence the warning
return std::string("");
@ -353,7 +356,7 @@ int colvarscript::run(int objc, unsigned char *const objv[])
}
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.");
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);
} else {
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");
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,
unsigned char *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 {
set_result_str(x_str);
}

View File

@ -16,7 +16,6 @@
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarbias.h"
#include "colvarproxy.h"
@ -25,6 +24,8 @@
#define COLVARSCRIPT_OK 0
class colvardeps;
class colvarscript {
private:
@ -161,6 +162,11 @@ public:
/// \param cmd Name of the command's function (e.g. "cv_units")
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)
/// \param cmd Name of the command's function (e.g. "cv_units")
char const *get_command_full_help(char const *cmd);
@ -263,6 +269,9 @@ private: // TODO
/// Internal identifiers of command strings
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)
char const **cmd_names;

View File

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

View File

@ -47,14 +47,10 @@
// If CVSCRIPT is not defined, this file yields the function prototypes
#ifndef CVSCRIPT
#ifdef __cplusplus
#define CVSCRIPT_COMM_PROTO(COMM) \
extern "C" int CVSCRIPT_COMM_FNAME(COMM)(void *, \
int, unsigned char *const *);
#else
#define CVSCRIPT_COMM_PROTO(COMM) \
int CVSCRIPT_COMM_FNAME(COMM)(void *, int, unsigned char *const *);
#endif
int, \
unsigned char *const *);
#define CVSCRIPT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS,FN_BODY) \
CVSCRIPT_COMM_PROTO(COMM)
@ -454,7 +450,8 @@ CVSCRIPT(cv_listcommands,
)
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,
"",
int const n_files = script->module()->index_file_names.size();
@ -467,19 +464,36 @@ CVSCRIPT(cv_listindexfiles,
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,
"Load data from a state file into all matching colvars and biases",
1, 1,
"prefix : string - Path to existing state file or input prefix",
char const *arg =
script->obj_to_str(script->get_module_cmd_arg(0, objc, objv));
script->proxy()->input_prefix() = cvm::state_file_prefix(arg);
if (script->module()->setup_input() == COLVARS_OK) {
return COLVARS_OK;
} else {
int error_code =
script->proxy()->set_input_prefix(cvm::state_file_prefix(arg));
error_code |= script->module()->setup_input();
if (error_code != COLVARS_OK) {
script->add_error_msg("Error loading state file");
return COLVARSCRIPT_ERROR;
}
return error_code;
)
CVSCRIPT(cv_loadfromstring,
@ -488,7 +502,8 @@ CVSCRIPT(cv_loadfromstring,
"buffer : string - String buffer containing the state information",
char const *arg =
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) {
return COLVARS_OK;
} else {
@ -560,8 +575,7 @@ CVSCRIPT(cv_save,
"prefix : string - Output prefix with trailing \".colvars.state\" gets removed)",
std::string const prefix =
cvm::state_file_prefix(script->obj_to_str(script->get_module_cmd_arg(0, objc, objv)));
script->proxy()->output_prefix() = prefix;
int error_code = COLVARS_OK;
int error_code = script->proxy()->set_output_prefix(prefix);
error_code |= script->module()->setup_output();
error_code |= script->module()->write_restart_file(prefix+
".colvars.state");
@ -578,10 +592,10 @@ CVSCRIPT(cv_savetostring,
)
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",
0, 1,
"T : float - New target temperature in K",
"T : float - New target temperature in K (internal use)",
char const *Targ =
script->obj_to_str(script->get_module_cmd_arg(0, objc, objv));
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,
"Get or set the current Colvars unit system\n"
"units : string - The current unit system",

View File

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

View File

@ -9,7 +9,7 @@
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",
0, 0,
"",
@ -17,6 +17,8 @@ CVSCRIPT(bias_bin,
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,
"Get the number of samples at the given grid bin (1D ABF only for now)\n"
"samples : integer - Number of samples",
@ -36,6 +38,25 @@ CVSCRIPT(bias_bincount,
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,
"Get the total number of grid points of this bias (1D ABF only for now)\n"
"Bins : integer - Number of grid points",

View File

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

View File

@ -9,7 +9,7 @@
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",
1, 1,
"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
// Colvars repository at GitHub.
#include <cstdlib>
#include <cstring>
#include "colvarmodule.h"
#include "colvartypes.h"
#include "colvarparse.h"
#include "colvaratoms.h"
#include "colvar_rotation_derivative.h"
#ifdef COLVARS_LAMMPS
// Use open-source Jacobi implementation
@ -204,14 +202,6 @@ cvm::quaternion::position_derivative_inner(cvm::rvector const &pos,
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
namespace {
inline void *new_Jacobi_solver(int size) {
@ -226,7 +216,7 @@ namespace {
int colvarmodule::rotation::init()
{
b_debug_gradients = false;
lambda = 0.0;
// lambda = 0.0;
cvm::main()->cite_feature("Optimal rotation via flexible fitting");
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()
{
@ -325,28 +334,26 @@ void colvarmodule::rotation::compute_overlap_matrix()
#ifndef COLVARS_LAMMPS
namespace {
namespace NR {
void diagonalize_matrix(cvm::matrix2d<cvm::real> &m,
cvm::vector1d<cvm::real> &eigval,
cvm::matrix2d<cvm::real> &eigvec)
void diagonalize_matrix(cvm::real m[4][4],
cvm::real eigval[4],
cvm::real eigvec[4][4])
{
eigval.resize(4);
eigval.reset();
eigvec.resize(4, 4);
eigvec.reset();
std::memset(eigval, 0, sizeof(cvm::real) * 4);
std::memset(eigvec, 0, sizeof(cvm::real) * 4 * 4);
// diagonalize
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) {
cvm::error("Too many iterations in jacobi diagonalization.\n"
"This is usually the result of an ill-defined set of atoms for "
"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
NR_Jacobi::transpose(eigvec.c_array());
NR_Jacobi::transpose(eigvec);
// normalize eigenvectors
for (size_t ie = 0; ie < 4; ie++) {
@ -375,27 +382,51 @@ void colvarmodule::rotation::calc_optimal_rotation(
C.reset();
build_correlation_matrix(pos1, pos2);
S.resize(4, 4);
S.reset();
calc_optimal_rotation_impl();
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();
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) {
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
MathEigen::Jacobi<cvm::real,
cvm::vector1d<cvm::real> &,
cvm::matrix2d<cvm::real> &> *ecalc =
cvm::real[4],
cvm::real[4][4]> *ecalc =
reinterpret_cast<MathEigen::Jacobi<cvm::real,
cvm::vector1d<cvm::real> &,
cvm::matrix2d<cvm::real> &> *>(jacobi);
cvm::real[4],
cvm::real[4][4]> *>(jacobi);
int ierror = ecalc->Diagonalize(S, S_eigval, S_eigvec);
if (ierror) {
@ -404,22 +435,9 @@ void colvarmodule::rotation::calc_optimal_rotation(
"rotational alignment (RMSD, rotateReference, etc).\n");
}
#else
diagonalize_matrix(S, S_eigval, S_eigvec);
NR::diagonalize_matrix(S, S_eigval, S_eigvec);
#endif
// 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;
q = cvm::quaternion{S_eigvec[0][0], S_eigvec[0][1], S_eigvec[0][2], S_eigvec[0][3]};
if (cvm::rotation::monitor_crossings) {
if (q_old.norm2() > 0.0) {
@ -431,178 +449,4 @@ void colvarmodule::rotation::calc_optimal_rotation(
}
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
#define COLVARTYPES_H
#include <sstream> // TODO specialize templates and replace this with iosfwd
#include <vector>
#ifdef COLVARS_LAMMPS
// Use open-source Jacobi implementation
#include "math_eigen_impl.h"
#endif
#include "colvarmodule.h"
#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
inline T * c_array()
{
@ -69,6 +81,12 @@ public:
return data;
}
/// Return a reference to the data
inline std::vector<T> const &data_array() const
{
return data;
}
inline ~vector1d()
{
data.clear();
@ -493,6 +511,12 @@ public:
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)
{
return rows[i];
@ -896,9 +920,6 @@ public:
zz = zzi;
}
/// Destructor
inline ~rmatrix()
{}
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
/// a wrapper for colvarmodule::quaternion)
class colvarmodule::rotation
{
public:
/// \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;
private:
/// Correlation matrix C (3, 3)
cvm::rmatrix C;
/// Overlap matrix S (4, 4)
cvm::matrix2d<cvm::real> S;
cvm::real S[4][4];
/// Eigenvalues of S
cvm::vector1d<cvm::real> S_eigval;
cvm::real S_eigval[4];
/// Eigenvectors of S
cvm::matrix2d<cvm::real> S_eigvec;
cvm::real S_eigvec[4][4];
/// Used for debugging gradients
cvm::matrix2d<cvm::real> S_backup;
cvm::real S_backup[4][4];
/// Derivatives of S
std::vector< cvm::matrix2d<cvm::rvector> > dS_1, dS_2;
/// Derivatives of leading eigenvalue
std::vector< cvm::rvector > dL0_1, dL0_2;
/// Derivatives of leading eigenvector
std::vector< cvm::vector1d<cvm::rvector> > dQ0_1, dQ0_2;
public:
/// \brief Perform gradient tests
bool b_debug_gradients;
/// Allocate space for the derivatives of the rotation
inline void request_group1_gradients(size_t n)
{
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));
}
/// \brief The rotation itself (implemented as a quaternion)
cvm::quaternion q;
/// Allocate space for the derivatives of the rotation
inline void request_group2_gradients(size_t n)
{
dS_2.resize(n, cvm::matrix2d<cvm::rvector>(4, 4));
dL0_2.resize(n, cvm::rvector(0.0, 0.0, 0.0));
dQ0_2.resize(n, cvm::vector1d<cvm::rvector>(4));
}
template <typename T1, typename T2>
friend struct rotation_derivative;
template<typename T1, typename T2>
friend void debug_gradients(
cvm::rotation &rot,
const std::vector<T1> &pos1,
const std::vector<T2> &pos2);
/// \brief Calculate the optimal rotation and store the
/// corresponding eigenvalue and eigenvector in the arguments l0 and
@ -1344,6 +1356,8 @@ public:
/// DOI: 10.1002/jcc.20110 PubMed: 15376254
void calc_optimal_rotation(std::vector<atom_pos> const &pos1,
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
int init();
@ -1478,6 +1492,11 @@ protected:
/// Build the correlation matrix C (used by calc_optimal_rotation())
void build_correlation_matrix(std::vector<cvm::atom_pos> const &pos1,
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())
void compute_overlap_matrix();

View File

@ -8,11 +8,10 @@
// Colvars repository at GitHub.
#include <vector>
#include <sstream>
#include <iostream>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvars_memstream.h"
@ -721,29 +720,43 @@ int colvarvalue::from_simple_string(std::string const &s)
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:
os << x.real_value;
os << real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
os << x.rvector_value;
os << rvector_value;
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
os << x.quaternion_value;
os << quaternion_value;
break;
case colvarvalue::type_vector:
os << x.vector1d_value;
os << vector1d_value;
break;
case colvarvalue::type_notset:
default:
os << "not set";
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;
}
@ -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, "
"which has not yet been assigned a data type.\n");
return is;
}
switch (x.type()) {
switch (type()) {
case colvarvalue::type_scalar:
is >> x.real_value;
is >> real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vectorderiv:
is >> x.rvector_value;
is >> rvector_value;
break;
case colvarvalue::type_unit3vector:
is >> x.rvector_value;
x.apply_constraints();
is >> rvector_value;
apply_constraints();
break;
case colvarvalue::type_quaternion:
is >> x.quaternion_value;
x.apply_constraints();
is >> quaternion_value;
apply_constraints();
break;
case colvarvalue::type_quaternionderiv:
is >> x.quaternion_value;
is >> quaternion_value;
break;
case colvarvalue::type_vector:
is >> x.vector1d_value;
is >> vector1d_value;
break;
case colvarvalue::type_notset:
default:
x.undef_op();
undef_op();
}
}
std::istream & operator >> (std::istream &is, colvarvalue &x)
{
x.read_from_stream_template_<std::istream>(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
{
switch (this->value_type) {

View File

@ -10,6 +10,8 @@
#ifndef COLVARVALUE_H
#define COLVARVALUE_H
#include <list>
#include "colvarmodule.h"
#include "colvartypes.h"
@ -120,7 +122,8 @@ public:
/// number and always behaves like it unless you change its type
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);
/// Copy constructor from real base type
@ -297,12 +300,31 @@ public:
/// Undefined operation
void undef_op() const;
private:
/// \brief Formatted output operator
friend std::ostream & operator << (std::ostream &os, colvarvalue const &q);
/// Generic stream writing function (formatted and not)
template <typename OST> void write_to_stream_template_(OST &os) const;
/// \brief Formatted input operator
friend std::istream & operator >> (std::istream &is, colvarvalue &q);
public:
/// 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
/// colvarvalue, given the current type assigned and the number of