def __init__(self, input_mdp_file): self.IO = mdFileIO() self.p = self.IO.readParamFile(input_mdp_file) # p for md parameters self.binw = 2 * self.p["half_boxboundary"] / self.p["binNum"] self.bins = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.colvars_coord = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.mdInitializer = mdEngine(self.p["nparticle"], self.p["box"], self.p["kb"],\ self.p["time_step"], self.p["temperature"], self.p["ndims"],\ self.p["mass"], self.p["thermoStatFlag"], self.getCurrentForce, self.p["frictCoeff"]) self.initializeForce = Force(self.p["kb"], self.p["time_step"], self.p["temperature"], self.p["ndims"], self.p["mass"], self.p["thermoStatFlag"], self.p["frictCoeff"]) # init coord and vel self.current_coord = np.zeros((self.p["nparticle"], self.p["ndims"]), dtype=np.float64) self.current_vel = self.mdInitializer.genVelocity() # init coord and vel if self.p["ndims"] == 1: self.colvars_force = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE_NN = np.zeros(len(self.bins), dtype=np.float64) self.colvars_count = np.zeros(len(self.bins), dtype=np.float64) self.colvars_hist = np.zeros(len(self.bins), dtype=np.float64) self.temp = np.zeros(len(self.bins), dtype=np.float64) self.biasingPotentialConv = np.zeros(len(self.bins), dtype=np.float64) self.biasingPotentialFromNN = np.zeros(len(self.bins), dtype=np.float64) if self.p["ndims"] == 2: self.colvars_force = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE_NN = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_count = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_hist = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.temp = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.biasingPotentialConv = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) self.biasingPotentialFromNN = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64)
class ABF(object): def __init__(self, input_mdp_file): self.IO = mdFileIO() self.p = self.IO.readParamFile(input_mdp_file) # p for md parameters self.bins = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.colvars_coord = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.mdInitializer = mdEngine(self.p["nparticle"], self.p["box"], self.p["kb"],\ self.p["time_step"], self.p["temperature"], self.p["ndims"],\ self.p["mass"], self.p["thermoStatFlag"], self.getCurrentForce, self.p["frictCoeff"]) self.initializeForce = Force(self.p["kb"], self.p["time_step"], self.p["temperature"], self.p["ndims"], self.p["mass"], self.p["thermoStatFlag"], self.p["frictCoeff"]) # init coord and vel self.current_coord = np.zeros((self.p["nparticle"], self.p["ndims"]), dtype=np.float64) self.current_vel = self.mdInitializer.genVelocity() # init coord and vel self.criteriaCounter = 0 self.criteriaFEBool = 0 if self.p["ndims"] == 1: self.colvars_force = np.zeros(len(self.bins), dtype=np.float64) self.colvars_force_tmp = np.zeros(len(self.bins), dtype=np.float64) self.colvars_force_NN = np.zeros(len(self.bins), dtype=np.float64) self.colvars_count = np.zeros(len(self.bins), dtype=np.float64) self.colvars_hist = np.zeros(len(self.bins), dtype=np.float64) self.criteria_hist = np.zeros(len(self.bins), dtype=np.float64) self.criteria_prev = np.zeros(len(self.bins), dtype=np.float64) self.criteria_curr = np.zeros(len(self.bins), dtype=np.float64) self.criteria_FreeE = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE_prev = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE_curr = np.zeros(len(self.bins), dtype=np.float64) if self.p["ndims"] == 2: self.colvars_force = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_force_tmp = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_force_NN = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_count = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_hist = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_hist = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_prev = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_curr = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_FreeE = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE_prev = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE_curr = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) def _forceHistDistrRecord(self, coord_x, coord_y, d): if self.p["ndims"] == 1: self.colvars_count[getIndices(coord_x, self.bins)] += 1 if self.p["ndims"] == 2: self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] += 1 def _forceDistrRecord(self, coord_x, updated_Fsys, coord_y, d): if self.p["ndims"] == 1: self.colvars_force[getIndices(coord_x, self.bins)] += updated_Fsys if self.p["ndims"] == 2: self.colvars_force[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] += updated_Fsys def _inverseGradient(self): """ cv == cartesian so return 1""" return 1 def _Jacobian(self): """ cv == cartesian -> ln|J| = 0 so return 0""" return 0 def _entropicCorrection(self): return self.p["kb"] * self.p["temperature"] * self._Jacobian() def _calBiasingForce(self, coord_x, coord_y, d): if (self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "no") or (self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes" and self.criteriaFEBool == 0): if self.p["ndims"] == 1: if self.colvars_count[getIndices(coord_x, self.bins)] == 0: return 0 else: return -( (self.colvars_force[getIndices(coord_x, self.bins)] / self.colvars_count[getIndices(coord_x, self.bins)] + self._entropicCorrection()) * self._inverseGradient()) if self.p["ndims"] == 2: if self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] == 0: return 0 else: return -((self.colvars_force[d][getIndices(coord_x, self.bins)][getIndices(coord_y, self.bins)] / self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices(coord_y, self.bins)] +\ self._entropicCorrection()) * self._inverseGradient()) if (self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes") and self.criteriaFEBool > 0: if self.p["ndims"] == 1: return -self.colvars_force_NN[getIndices(coord_x, self.bins)] if self.p["ndims"] == 2: return -self.colvars_force_NN[d][getIndices( coord_x, self.bins)][getIndices(coord_y, self.bins)] def _abfDecorator(func): def _wrapper(self, coord_x, d, vel, coord_y): Fabf = func(self, coord_x, d, vel, coord_y) currentFsys = self.initializeForce.getForce( coord_x, d, vel, coord_y) self._forceDistrRecord(coord_x, currentFsys, coord_y, d) self._forceHistDistrRecord(coord_x, coord_y, d) return Fabf + currentFsys return _wrapper @_abfDecorator def getCurrentForce(self, coord_x, d, vel, coord_y): if self.p["abfCheckFlag"] == "no" and self.p["nnCheckFlag"] == "no": Fabf = 0 else: Fabf = self._calBiasingForce(coord_x, coord_y, d) return Fabf def _criteriaModCurr(self): if self.criteriaCounter <= 1: self.criteria_prev = copy.deepcopy( self.colvars_hist / np.sum(self.colvars_hist)) # w/o unbiasing else: self.criteria_curr = copy.deepcopy( self.colvars_hist / np.sum(self.colvars_hist)) # w/o unbiasing def _criteriaModPrev(self): self.criteria_prev = copy.deepcopy(self.criteria_curr) def _criteriaCheck(self, holder, prev, curr, msERROR): if self.criteriaCounter >= 2: holder = ((prev - curr) / curr)**2 holder[np.isnan(holder)] = 0.0 holder[np.isinf(holder)] = 0.0 holder[np.isneginf(holder)] = 0.0 holder = holder[holder > msERROR] return not holder.size return False def _accumulateColvarsHist(self): for n in range(self.p["nparticle"]): if self.p["ndims"] == 1: self.colvars_hist[getIndices(self.current_coord[n][0], self.bins)] += 1 elif self.p["ndims"] == 2: self.colvars_hist[getIndices(self.current_coord[n][0], self.bins)][getIndices( self.current_coord[n][1], self.bins)] += 1 def getCurrentFreeEnergy(self): if self.p["nnCheckFlag"] == "no": self.colvars_force_tmp = copy.deepcopy(self.colvars_force / self.colvars_count) self.colvars_force_tmp[np.isnan(self.colvars_force_tmp)] = 0 self.colvars_force_tmp = paddingRightMostBin( self.colvars_force_tmp) else: self.colvars_force_tmp = copy.deepcopy(self.colvars_force_NN) self.colvars_force_tmp[np.isnan(self.colvars_force_tmp)] = 0 self.colvars_force_tmp = paddingRightMostBin( self.colvars_force_tmp) self.colvars_FreeE = integrator(self.p["ndims"], self.colvars_coord, self.colvars_force_tmp, self.p["half_boxboundary"], self.p["init_frame"], self.p["shiftConst"], "tempFreeE.dat") def _learningProxy(self): if self.p["nnCheckFlag"] == "yes": output = trainingANN("loss.dat", "hyperparam.dat", self.p["ndims"], len(self.bins)) self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan( self.colvars_force)] = 0 # 0/0 = nan n/0 = inf self.colvars_force = paddingRightMostBin(self.colvars_force) if self.p["init_frame"] < self.p["earlyStopCheck"] * self.p[ "switchSteps"]: self.colvars_force_NN = \ output.training(self.colvars_coord, self.colvars_force, self.p["earlyLearningRate"], self.p["earlyRegularCoeff"], self.p["earlyEpoch"], self.p["nnOutputFreq"]) else: self.colvars_force_NN = \ output.training(self.colvars_coord, self.colvars_force, self.p["lateLearningRate"], self.p["lateRegularCoeff"], self.p["lateEpoch"], self.p["nnOutputFreq"]) self.colvars_force = (self.colvars_force * self.colvars_count) def mdrun(self): init_real_world_time = time.time() # PRE-PROCESSING lammpstrj = open( "m%.1f_T%.3f_gamma%.4f_len_%d_%s_%s.lammpstrj" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"], self.p["abfCheckFlag"], self.p["nnCheckFlag"]), "w") forceOnCVs = open( "Force_m%.1fT%.3f_gamma%.4f_len_%d_%s_%s.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"], self.p["abfCheckFlag"], self.p["nnCheckFlag"]), "w") histogramOnCVs = open( "Hist_m%.1fT%.3f_gamma%.4f_len_%d_%s_%s.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"], self.p["abfCheckFlag"], self.p["nnCheckFlag"]), "w") withANN = open("instantForceWANN_" + str(self.p["ndims"]) + "D.dat", "a") woANN = open("instantForceWOANN_" + str(self.p["ndims"]) + "D.dat", "a") earlyFreeE = open("earlyFreeE.dat", "a") FinalFE = open("FreeE.dat", "w") # START of the simulation self.IO.writeParams(self.p) self.IO.lammpsFormatColvarsOutput(self.p["ndims"], self.p["nparticle"], self.p["half_boxboundary"], self.p["init_frame"], self.current_coord, lammpstrj, self.p["writeFreq"]) self.IO.printCurrentStatus(self.p["init_frame"], init_real_world_time) while self.p["init_frame"] < self.p["total_frame"]: self.p["init_frame"] += 1 self.IO.printCurrentStatus(self.p["init_frame"], init_real_world_time) self.mdInitializer.checkTargetTemperature(self.current_vel, self.p["init_frame"], self.p["total_frame"]) if self.p["init_frame"] % self.p["earlyStopCheck"] == 0 and self.p[ "init_frame"] != 0 and self.p["abfCheckFlag"] == "yes": self.criteriaCounter += 1 self._criteriaModCurr() if self._criteriaCheck(self.criteria_hist, self.criteria_prev, self.criteria_curr, self.p["trainingCriteria"]): if self.p["nnCheckFlag"] == "no": self.getCurrentFreeEnergy() self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_FreeE, self.colvars_hist, self.p["init_frame"], earlyFreeE) self.temp = paddingRightMostBin(self.colvars_force / self.colvars_count) self.IO.certainFrequencyOutput(self.colvars_coord, self.temp, self.colvars_count, self.p["init_frame"], woANN) else: self._learningProxy() self.getCurrentFreeEnergy() self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_FreeE, self.colvars_hist, self.p["init_frame"], earlyFreeE) self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_force_NN, self.colvars_count, self.p["init_frame"], withANN) # retrieve FE if self.criteriaFEBool % 2 == 0: self.colvars_FreeE_prev = copy.deepcopy( self.colvars_FreeE) else: self.colvars_FreeE_curr = copy.deepcopy( self.colvars_FreeE) self.criteriaFEBool += 1 # To clean invalid data (inf, nan), we let some data == 0, this would cause issues when evaluating criteria, so we should at least do twice if self._criteriaCheck( self.criteria_FreeE, self.colvars_FreeE_prev, self.colvars_FreeE_curr, self.p["simlEndCriteria"] ) and self.criteriaFEBool >= 2: break # retrieve FE if self.criteriaCounter > 1: self._criteriaModPrev() self.mdInitializer.velocityVerletSimple(self.current_coord, self.current_vel) self._accumulateColvarsHist() self.IO.lammpsFormatColvarsOutput(self.p["ndims"], self.p["nparticle"], self.p["half_boxboundary"], self.p["init_frame"], self.current_coord, lammpstrj, self.p["writeFreq"]) # END of the simulation # POST-PROCESSING probability = copy.deepcopy( (self.colvars_hist / np.sum(self.colvars_hist))) probability = paddingRightMostBin(probability) self.IO.propertyOnColvarsOutput(self.bins, probability, self.colvars_hist, histogramOnCVs) self.IO.propertyOnColvarsOutput(self.bins, self.colvars_FreeE, self.colvars_hist, FinalFE) if self.p["nnCheckFlag"] == "yes": self.IO.propertyOnColvarsOutput(self.bins, self.colvars_force_NN, self.colvars_count, forceOnCVs) else: self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan(self.colvars_force)] = 0 self.colvars_force = paddingRightMostBin(self.colvars_force) self.IO.propertyOnColvarsOutput(self.bins, self.colvars_force, self.colvars_count, forceOnCVs) # ndims >= 2 -> plot using matplotlib if self.p["ndims"] == 2: s = rendering(self.p["ndims"], self.p["half_boxboundary"], self.p["binNum"], self.p["temperature"]) s.render( probability, name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "boltzDist" + str(self.p["ndims"]) + "D")) s.render( self.colvars_FreeE, name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "FEsurface" + str(self.p["ndims"]) + "D")) if self.p["nnCheckFlag"] == "yes": try: s.render(self.colvars_force_NN[0], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcex" + str(self.p["ndims"]) + "D")) s.render(self.colvars_force_NN[1], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcey" + str(self.p["ndims"]) + "D")) except: # no chance to train pass else: s.render(self.colvars_force[0], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcex" + str(self.p["ndims"]) + "D")) s.render(self.colvars_force[1], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcey" + str(self.p["ndims"]) + "D")) # Close files, mkdir and mv files self.IO.closeAllFiles(lammpstrj, forceOnCVs, histogramOnCVs, withANN, woANN, earlyFreeE, FinalFE) self.IO.makeDirAndMoveFiles(self.p["ndims"], self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"],\ self.p["abfCheckFlag"], self.p["nnCheckFlag"], __class__.__name__)
class ABP(object): def __init__(self, input_mdp_file): self.IO = mdFileIO() self.p = self.IO.readParamFile(input_mdp_file) # p for md parameters self.binw = 2 * self.p["half_boxboundary"] / self.p["binNum"] self.bins = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.colvars_coord = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.mdInitializer = mdEngine(self.p["nparticle"], self.p["box"], self.p["kb"],\ self.p["time_step"], self.p["temperature"], self.p["ndims"],\ self.p["mass"], self.p["thermoStatFlag"], self.getCurrentForce, self.p["frictCoeff"]) self.initializeForce = Force(self.p["kb"], self.p["time_step"], self.p["temperature"], self.p["ndims"], self.p["mass"], self.p["thermoStatFlag"], self.p["frictCoeff"]) # init coord and vel self.current_coord = np.zeros((self.p["nparticle"], self.p["ndims"]), dtype=np.float64) self.current_vel = self.mdInitializer.genVelocity() self.criteriaCounter = 0 self.criteriaFEBool = 0 if self.p["ndims"] == 1: self.colvars_force = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE_NN = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE_prev = np.zeros(len(self.bins), dtype=np.float64) self.colvars_FreeE_curr = np.zeros(len(self.bins), dtype=np.float64) self.colvars_count = np.zeros(len(self.bins), dtype=np.float64) self.colvars_hist = np.zeros(len(self.bins), dtype=np.float64) self.criteria_hist = np.zeros(len(self.bins), dtype=np.float64) self.criteria_FreeE = np.zeros(len(self.bins), dtype=np.float64) self.criteria_prev = np.zeros(len(self.bins), dtype=np.float64) self.criteria_curr = np.zeros(len(self.bins), dtype=np.float64) self.biasingPotentialConv = np.zeros(len(self.bins), dtype=np.float64) self.biasingPotentialFromNN = np.zeros(len(self.bins), dtype=np.float64) if self.p["ndims"] == 2: self.colvars_force = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE_NN = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE_prev = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_FreeE_curr = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_count = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_hist = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_hist = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_FreeE = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_prev = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.criteria_curr = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) self.biasingPotentialConv = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) self.biasingPotentialFromNN = np.zeros( (len(self.bins), len(self.bins)), dtype=np.float64) def _forceHistDistrRecord(self, coord_x, coord_y, d): if self.p["ndims"] == 1: self.colvars_count[getIndices(coord_x, self.bins)] += 1 if self.p["ndims"] == 2: self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] += 1 def _forceDistrRecord(self, coord_x, updated_Fsys, coord_y, d): if self.p["ndims"] == 1: self.colvars_force[getIndices(coord_x, self.bins)] += updated_Fsys if self.p["ndims"] == 2: self.colvars_force[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] += updated_Fsys def _biasingPotential(self, coord_x, coord_y=None): if self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes": if self.p["ndims"] == 1: if self.p["init_frame"] <= self.p[ "earlyStopCheck"]: # initial sweep return 0 else: return self.biasingPotentialFromNN[getIndices( coord_x, self.bins)] if self.p["ndims"] == 2: if self.p["init_frame"] <= self.p[ "earlyStopCheck"]: # initial sweep return 0 else: return self.biasingPotentialFromNN[getIndices( coord_x, self.bins)][getIndices(coord_y, self.bins)] elif self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "no": if self.p["ndims"] == 1: if self.p["init_frame"] <= self.p["earlyStopCheck"]: return 0 else: return self.biasingPotentialConv[getIndices( coord_x, self.bins)] if self.p["ndims"] == 2: if self.p["init_frame"] <= self.p["earlyStopCheck"]: return 0 else: return self.biasingPotentialConv[getIndices( coord_x, self.bins)][getIndices(coord_y, self.bins)] else: return 0 def _calBiasingForce(self, coord_x, coord_y, d): if (self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "no") or (self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes" and self.p["init_frame"] <= self.p["earlyStopCheck"]): bsForce = copy.deepcopy(self.colvars_FreeE) elif (self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes") and self.p["init_frame"] > self.p["earlyStopCheck"]: bsForce = copy.deepcopy(self.colvars_FreeE_NN) elif self.p["abfCheckFlag"] == "no" and self.p["nnCheckFlag"] == "no": return 0 if self.p["ndims"] == 1: bsForce = np.diff(bsForce) bsForce = np.append(bsForce, bsForce[-1]) # padding to the right legnth bsForce = (bsForce / self.binw) return bsForce[getIndices(coord_x, self.bins)] if self.p["ndims"] == 2: if d == 0: bsForce = np.diff(bsForce, axis=0) # axis=0 for x; axis=1 for y bsForce = np.append(bsForce, [bsForce[-1, :]], axis=0) # padding to the right length bsForce = (bsForce / self.binw) elif d == 1: bsForce = np.diff(bsForce, axis=1) bsForce = np.append(bsForce, bsForce[:, -1][:, np.newaxis], axis=1) # padding to the right length bsForce = (bsForce / self.binw) return bsForce[getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] def _abpDecorator(func): def _wrapper(self, coord_x, d, vel, coord_y): Fabf = func(self, coord_x, d, vel, coord_y) currentFsys = self.initializeForce.getForce( coord_x, d, vel, coord_y) self._forceDistrRecord(coord_x, currentFsys, coord_y, d) self._forceHistDistrRecord(coord_x, coord_y, d) return Fabf + currentFsys return _wrapper @_abpDecorator def getCurrentForce(self, coord_x, d, vel, coord_y): Fabf = self._calBiasingForce(coord_x, coord_y, d) return Fabf def _probability(self): """ 1. unbias the historgram 2. calculate the partition function 3. calculate the probability and return it """ if self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes": maxValueOfBiasingPotential = np.amax(self.biasingPotentialFromNN) elif self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "no": maxValueOfBiasingPotential = np.amax(self.biasingPotentialConv) else: maxValueOfBiasingPotential = 0 if self.p["ndims"] == 1: rwHist = np.zeros(len(self.bins), dtype=np.float64) for i in range(len(self.colvars_hist)): rwHist[i] = self.colvars_hist[i] * np.exp(self._biasingPotential(self.bins[i]) / self.p["kb"] / self.p["temperature"]) *\ np.exp(-maxValueOfBiasingPotential / self.p["kb"] / self.p["temperature"]) if self.p["ndims"] == 2: rwHist = np.zeros((len(self.bins), len(self.bins)), dtype=np.float64) for i in range(len(self.colvars_hist)): for j in range(len(self.colvars_hist)): rwHist[i][j] = self.colvars_hist[i][j] * np.exp(self._biasingPotential(self.bins[i], self.bins[j]) / self.p["kb"] / self.p["temperature"]) *\ np.exp(-maxValueOfBiasingPotential / self.p["kb"] / self.p["temperature"]) partitionFunc = np.sum(rwHist) probabilityDistr = rwHist / partitionFunc return probabilityDistr def getCurrentFreeEnergy(self): self.colvars_FreeE = -self.p["kb"] * self.p["temperature"] * np.log( self._probability()) self.colvars_FreeE[np.isneginf( self.colvars_FreeE)] = 0.0 # deal with -inf self.colvars_FreeE[np.isinf( self.colvars_FreeE)] = 0.0 # deal with inf self.colvars_FreeE = paddingRightMostBin(self.colvars_FreeE) def _updateBiasingPotential(self): self.biasingPotentialFromNN = -copy.deepcopy( self.colvars_FreeE_NN) # phi(x) = -Fhat(x); for ANN self.biasingPotentialConv = -copy.deepcopy( self.colvars_FreeE) # phi(x) = -Fhat(x); for non-ANN def _criteriaModCurr(self): if self.criteriaCounter <= 1: self.criteria_prev = self._probability() else: self.criteria_curr = self._probability() def _criteriaModPrev(self): self.criteria_prev = copy.deepcopy(self.criteria_curr) def _criteriaCheck(self, holder, prev, curr, msERROR): if self.criteriaCounter >= 2: holder = ((prev - curr) / curr)**2 holder[np.isnan(holder)] = 0.0 holder[np.isinf(holder)] = 0.0 holder[np.isneginf(holder)] = 0.0 holder = holder[holder > msERROR] return not holder.size return False def _learningProxy(self): if self.p["nnCheckFlag"] == "yes": output = trainingANN("loss.dat", "hyperparam.dat", self.p["ndims"], len(self.bins), self.binw) if self.p["init_frame"] < self.p["earlyStopCheck"] * self.p[ "switchSteps"]: self.colvars_FreeE_NN , _ = \ output.training(self.colvars_coord, self.colvars_FreeE, self.p["earlyLearningRate"], self.p["earlyRegularCoeff"], self.p["earlyEpoch"], self.p["nnOutputFreq"]) else: self.colvars_FreeE_NN , _ = \ output.training(self.colvars_coord, self.colvars_FreeE, self.p["lateLearningRate"], self.p["lateRegularCoeff"], self.p["lateEpoch"], self.p["nnOutputFreq"]) def _accumulateColvarsHist(self): for n in range(self.p["nparticle"]): if self.p["ndims"] == 1: self.colvars_hist[getIndices(self.current_coord[n][0], self.bins)] += 1 elif self.p["ndims"] == 2: self.colvars_hist[getIndices(self.current_coord[n][0], self.bins)][getIndices( self.current_coord[n][1], self.bins)] += 1 def _resetColvarsHist(self): self.colvars_hist.fill(0) def mdrun(self): init_real_world_time = time.time() # PRE-PROCESSING lammpstrj = open( "m%.1f_T%.5f_gamma%.2f_len_%d.lammpstrj" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"]), "w") forceOnCVs = open( "Force_m%.1fT%.5f_gamma%.2f_len_%d.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"]), "w") freeEOnCVs = open( "FreeE_m%.1fT%.5f_gamma%.2f_len_%d.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"]), "w") histogramOnCVs = open( "Hist_m%.1fT%.5f_gamma%.2f_len_%d.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"]), "w") annABP = open("instantFreeEWANN_" + str(self.p["ndims"]) + "D.dat", "a") convABP = open("instantFreeEWOANN_" + str(self.p["ndims"]) + "D.dat", "a") tempHist = open("tempHist.dat", "a") tempBsp = open("tempBsp.dat", "a") earlyFreeE = open("earlyFreeE.dat", "a") # START of the simulation self.IO.writeParams(self.p) self.IO.lammpsFormatColvarsOutput(self.p["ndims"], self.p["nparticle"], self.p["half_boxboundary"], self.p["init_frame"], self.current_coord, lammpstrj, self.p["writeFreq"]) self.IO.printCurrentStatus(self.p["init_frame"], init_real_world_time) while self.p["init_frame"] < self.p["total_frame"]: self.p["init_frame"] += 1 self.IO.printCurrentStatus(self.p["init_frame"], init_real_world_time) self.mdInitializer.checkTargetTemperature(self.current_vel, self.p["init_frame"], self.p["total_frame"]) # early stop if self.p["init_frame"] % self.p["earlyStopCheck"] == 0 and self.p[ "init_frame"] != 0 and self.p["abfCheckFlag"] == "yes": self.criteriaCounter += 1 self._criteriaModCurr() if self._criteriaCheck(self.criteria_hist, self.criteria_prev, self.criteria_curr, self.p["trainingCriteria"]): self.getCurrentFreeEnergy() if self.p["nnCheckFlag"] == "no": self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_FreeE, self.colvars_hist, self.p["init_frame"], earlyFreeE) else: self._learningProxy() self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_FreeE_NN, self.colvars_hist, self.p["init_frame"], earlyFreeE) self._updateBiasingPotential() # retrieve FE if self.criteriaFEBool % 2 == 0: if self.p["nnCheckFlag"] == "yes": self.colvars_FreeE_prev = copy.deepcopy( self.colvars_FreeE_NN) else: self.colvars_FreeE_prev = copy.deepcopy( self.colvars_FreeE) else: if self.p["nnCheckFlag"] == "yes": self.colvars_FreeE_curr = copy.deepcopy( self.colvars_FreeE_NN) else: self.colvars_FreeE_curr = copy.deepcopy( self.colvars_FreeE) self.criteriaFEBool += 1 # To clean invalid data (inf, nan), we let some data == 0, this would cause issues when evaluating criteria, so we should at least do twice if self._criteriaCheck( self.criteria_FreeE, self.colvars_FreeE_prev, self.colvars_FreeE_curr, self.p["simlEndCriteria"] ) and self.criteriaFEBool >= 2: break # retrieve FE self._resetColvarsHist() if self.criteriaCounter > 1: self._criteriaModPrev() self.mdInitializer.velocityVerletSimple(self.current_coord, self.current_vel) self._accumulateColvarsHist() self.IO.lammpsFormatColvarsOutput(self.p["ndims"], self.p["nparticle"], self.p["half_boxboundary"], self.p["init_frame"], self.current_coord, lammpstrj, self.p["writeFreq"]) # END of the simulation # POST-PROCESSING probability = copy.deepcopy( (self.colvars_hist / np.sum(self.colvars_hist))) probability = paddingRightMostBin(probability) self.IO.propertyOnColvarsOutput(self.bins, probability, self.colvars_hist, histogramOnCVs) self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan(self.colvars_force)] = 0 self.colvars_force = paddingRightMostBin(self.colvars_force) self.IO.propertyOnColvarsOutput(self.bins, self.colvars_force, self.colvars_count, forceOnCVs) if self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes": self.IO.propertyOnColvarsOutput(self.bins, self.colvars_FreeE_NN, self.colvars_hist, freeEOnCVs) else: self.IO.propertyOnColvarsOutput(self.bins, self.colvars_FreeE, self.colvars_hist, freeEOnCVs) if self.p["ndims"] == 2: s = rendering(self.p["ndims"], self.p["half_boxboundary"], self.p["binNum"], self.p["temperature"]) s.render( self.colvars_FreeE, name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "FEsurface_Original" + str(self.p["ndims"]) + "D")) s.render( self.colvars_force[0], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forceX_UnderABP" + str(self.p["ndims"]) + "D")) s.render( self.colvars_force[1], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forceY_UnderABP" + str(self.p["ndims"]) + "D")) s.render( probability, name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "boltzDistr_NN" + str(self.p["ndims"]) + "D")) if self.p["abfCheckFlag"] == "yes" and self.p[ "nnCheckFlag"] == "yes": s.render(self.colvars_FreeE_NN, name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "FEsurface_NN" + str(self.p["ndims"]) + "D")) # Close files, mdkir and mv files self.IO.closeAllFiles(lammpstrj, forceOnCVs, freeEOnCVs, histogramOnCVs, annABP, convABP, tempHist, tempBsp, earlyFreeE) self.IO.makeDirAndMoveFiles(self.p["ndims"], self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"],\ self.p["abfCheckFlag"], self.p["nnCheckFlag"], __class__.__name__)
class ABF(object): def __init__(self, input_mdp_file): self.IO = mdFileIO() self.p = self.IO.readParamFile(input_mdp_file) # p for md parameters self.bins = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.colvars_coord = np.linspace(-self.p["half_boxboundary"], self.p["half_boxboundary"], self.p["binNum"] + 1, dtype=np.float64) self.mdInitializer = mdEngine(self.p["nparticle"], self.p["box"], self.p["kb"],\ self.p["time_step"], self.p["temperature"], self.p["ndims"],\ self.p["mass"], self.p["thermoStatFlag"], self.getCurrentForce, self.p["frictCoeff"]) self.initializeForce = Force(self.p["kb"], self.p["time_step"], self.p["temperature"], self.p["ndims"], self.p["mass"], self.p["thermoStatFlag"], self.p["frictCoeff"]) # init coord and vel self.current_coord = np.zeros((self.p["nparticle"], self.p["ndims"]), dtype=np.float64) self.current_vel = self.mdInitializer.genVelocity() # init coord and vel if self.p["ndims"] == 1: self.colvars_force = np.zeros(len(self.bins), dtype=np.float64) self.colvars_force_NN = np.zeros(len(self.bins), dtype=np.float64) self.colvars_count = np.zeros(len(self.bins), dtype=np.float64) if self.p["ndims"] == 2: self.colvars_force = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_force_NN = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) self.colvars_count = np.zeros( (self.p["ndims"], len(self.bins), len(self.bins)), dtype=np.float64) def _forceHistDistrRecord(self, coord_x, coord_y, d): if self.p["ndims"] == 1: self.colvars_count[getIndices(coord_x, self.bins)] += 1 if self.p["ndims"] == 2: self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] += 1 def _forceDistrRecord(self, coord_x, updated_Fsys, coord_y, d): if self.p["ndims"] == 1: self.colvars_force[getIndices(coord_x, self.bins)] += updated_Fsys if self.p["ndims"] == 2: self.colvars_force[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] += updated_Fsys def _inverseGradient(self): """ cv == cartesian so return 1""" return 1 def _Jacobian(self): """ cv == cartesian -> ln|J| = 0 so return 0""" return 0 def _entropicCorrection(self): return self.p["kb"] * self.p["temperature"] * self._Jacobian() def _calBiasingForce(self, coord_x, coord_y, d): if self.p["ndims"] == 1: if self.colvars_count[getIndices(coord_x, self.bins)] == 0: return 0 else: return -( (self.colvars_force[getIndices(coord_x, self.bins)] / self.colvars_count[getIndices(coord_x, self.bins)] + self._entropicCorrection()) * self._inverseGradient()) if self.p["ndims"] == 2: if self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices( coord_y, self.bins)] == 0: return 0 else: return -((self.colvars_force[d][getIndices(coord_x, self.bins)][getIndices(coord_y, self.bins)] / self.colvars_count[d][getIndices(coord_x, self.bins)][getIndices(coord_y, self.bins)] +\ self._entropicCorrection()) * self._inverseGradient()) def _abfDecorator(func): def _wrapper(self, coord_x, d, vel, coord_y): Fabf = func(self, coord_x, d, vel, coord_y) currentFsys = self.initializeForce.getForce( coord_x, d, vel, coord_y) self._forceDistrRecord(coord_x, currentFsys, coord_y, d) self._forceHistDistrRecord(coord_x, coord_y, d) return Fabf + currentFsys return _wrapper @_abfDecorator def getCurrentForce(self, coord_x, d, vel, coord_y): if self.p["abfCheckFlag"] == "no" and self.p["nnCheckFlag"] == "no": Fabf = 0 elif self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "no": Fabf = self._calBiasingForce(coord_x, coord_y, d) elif self.p["abfCheckFlag"] == "yes" and self.p["nnCheckFlag"] == "yes": if self.p["init_frame"] < self.p["trainingFreq"]: Fabf = self._calBiasingForce(coord_x, coord_y, d) else: # ANN takes over here; reload the previous training model tf.reset_default_graph() with tf.Session() as sess: Saver = tf.train.import_meta_graph("net" + str(self.p["ndims"]) + "D" + "/netSaver.ckpt.meta") Saver.restore( sess, tf.train.latest_checkpoint("net" + str(self.p["ndims"]) + "D/")) graph = tf.get_default_graph() #y_estimatedOP = graph.get_operation_by_name("criticalOP") # get tensor with suffix :0 layerOutput = graph.get_tensor_by_name("annOutput:0") if self.p["ndims"] == 1: coord_x = np.array([coord_x])[:, np.newaxis] CV = graph.get_tensor_by_name("colvars:0") Fabf = -sess.run(layerOutput, feed_dict={ CV: coord_x }).reshape(self.p["ndims"])[d] if self.p["ndims"] == 2: coord_x = np.array([coord_x])[:, np.newaxis] coord_y = np.array([coord_y])[:, np.newaxis] CV_x = graph.get_tensor_by_name("colvars_x:0") CV_y = graph.get_tensor_by_name("colvars_y:0") Fabf = -sess.run(layerOutput, feed_dict={ CV_x: coord_x, CV_y: coord_y }).reshape(self.p["ndims"])[d] tf.reset_default_graph() return Fabf def _learningProxy(self): if self.p["nnCheckFlag"] == "yes": if self.p["init_frame"] % self.p["trainingFreq"] == 0 and self.p[ "init_frame"] != 0: output = trainingANN("loss.dat", "hyperparam.dat", self.p["ndims"], len(self.bins)) self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan( self.colvars_force)] = 0 # 0/0 = nan n/0 = inf self.colvars_force = paddingRightMostBin(self.colvars_force) if self.p["init_frame"] < self.p["trainingFreq"] * self.p[ "switchSteps"]: self.colvars_force_NN = \ output.training(self.colvars_coord, self.colvars_force, self.p["earlyLearningRate"], self.p["earlyRegularCoeff"], self.p["earlyEpoch"], self.p["nnOutputFreq"]) else: self.colvars_force_NN = \ output.training(self.colvars_coord, self.colvars_force, self.p["lateLearningRate"], self.p["lateRegularCoeff"], self.p["lateEpoch"], self.p["nnOutputFreq"]) self.colvars_force = (self.colvars_force * self.colvars_count) def mdrun(self): init_real_world_time = time.time() # PRE-PROCESSING lammpstrj = open( "m%.1f_T%.3f_gamma%.4f_len_%d_%s_%s.lammpstrj" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"], self.p["abfCheckFlag"], self.p["nnCheckFlag"]), "w") forceOnCVs = open( "Force_m%.1fT%.3f_gamma%.4f_len_%d_%s_%s.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"], self.p["abfCheckFlag"], self.p["nnCheckFlag"]), "w") histogramOnCVs = open( "Hist_m%.1fT%.3f_gamma%.4f_len_%d_%s_%s.dat" % (self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"], self.p["abfCheckFlag"], self.p["nnCheckFlag"]), "w") withANN = open("instantForceWANN_" + str(self.p["ndims"]) + "D.dat", "a") woANN = open("instantForceWOANN_" + str(self.p["ndims"]) + "D.dat", "a") # START of the simulation self.IO.writeParams(self.p) self.IO.lammpsFormatColvarsOutput(self.p["ndims"], self.p["nparticle"], self.p["half_boxboundary"], self.p["init_frame"], self.current_coord, lammpstrj, self.p["writeFreq"]) self.IO.printCurrentStatus(self.p["init_frame"], init_real_world_time) while self.p["init_frame"] < self.p["total_frame"]: self.p["init_frame"] += 1 self.IO.printCurrentStatus(self.p["init_frame"], init_real_world_time) self.mdInitializer.checkTargetTemperature(self.current_vel, self.p["init_frame"], self.p["total_frame"]) if self.p["init_frame"] % self.p["trainingFreq"] == 0 and self.p[ "init_frame"] != 0 and self.p[ "abfCheckFlag"] == "yes" and self.p[ "nnCheckFlag"] == "yes": self._learningProxy() self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan(self.colvars_force)] = 0 self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_force_NN, self.colvars_count, self.p["init_frame"], self.p["certainOutFreq"], withANN) self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_force, self.colvars_count, self.p["init_frame"], self.p["certainOutFreq"], woANN) self.colvars_force = (self.colvars_force * self.colvars_count) if self.p["init_frame"] % self.p["certainOutFreq"] == 0 and self.p[ "init_frame"] != 0 and self.p["nnCheckFlag"] == "no": self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan(self.colvars_force)] = 0 self.IO.certainFrequencyOutput(self.colvars_coord, self.colvars_force, self.colvars_count, self.p["init_frame"], self.p["certainOutFreq"], woANN) self.colvars_force = (self.colvars_force * self.colvars_count) self.mdInitializer.velocityVerletSimple(self.current_coord, self.current_vel) self.IO.lammpsFormatColvarsOutput(self.p["ndims"], self.p["nparticle"], self.p["half_boxboundary"], self.p["init_frame"], self.current_coord, lammpstrj, self.p["writeFreq"]) # END of the simulation # POST-PROCESSING probability = self.colvars_count / ( np.sum(self.colvars_count) / self.p["ndims"] ) # both numerator and denominator should actually be divided by two but this would be cacncelled probability = paddingRightMostBin(probability) self.IO.propertyOnColvarsOutput(self.bins, probability, self.colvars_count / 2, histogramOnCVs) if self.p["nnCheckFlag"] == "yes": self.IO.propertyOnColvarsOutput(self.bins, self.colvars_force_NN, self.colvars_count, forceOnCVs) else: self.colvars_force = (self.colvars_force / self.colvars_count) self.colvars_force[np.isnan(self.colvars_force)] = 0 self.colvars_force = paddingRightMostBin(self.colvars_force) self.IO.propertyOnColvarsOutput(self.bins, self.colvars_force, self.colvars_count, forceOnCVs) # ndims >= 2 -> plot using matplotlib if self.p["ndims"] == 2: s = rendering(self.p["ndims"], self.p["half_boxboundary"], self.p["binNum"], self.p["temperature"]) s.render( probability[0], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "boltzDist" + str(self.p["ndims"]) + "D")) if self.p["nnCheckFlag"] == "yes": s.render(self.colvars_force_NN[0], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcex" + str(self.p["ndims"]) + "D")) s.render(self.colvars_force_NN[1], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcey" + str(self.p["ndims"]) + "D")) else: s.render(self.colvars_force[0], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcex" + str(self.p["ndims"]) + "D")) s.render(self.colvars_force[1], name=str(self.p["abfCheckFlag"] + "_" + self.p["nnCheckFlag"] + "_" + "forcey" + str(self.p["ndims"]) + "D")) # Close files, mkdir and mv files self.IO.closeAllFiles(lammpstrj, forceOnCVs, histogramOnCVs, withANN, woANN) self.IO.makeDirAndMoveFiles(self.p["ndims"], self.p["mass"], self.p["temperature"], self.p["frictCoeff"], self.p["total_frame"],\ self.p["abfCheckFlag"], self.p["nnCheckFlag"], __class__.__name__)