diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index 031c5de1bc..fc9a6a76ed 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -307,7 +307,10 @@ def _get_natoms_and_nframes( natoms = len(atom_types[0]) else: natoms = len(atom_types) - coords = np.reshape(np.array(coords), [-1, natoms * 3]) + if natoms == 0: + assert coords.size == 0 + else: + coords = np.reshape(np.array(coords), [-1, natoms * 3]) nframes = coords.shape[0] return natoms, nframes @@ -415,7 +418,7 @@ def _prepare_feed_dict( atom_types = np.array(atom_types, dtype=int).reshape([-1, natoms]) else: atom_types = np.array(atom_types, dtype=int).reshape([-1]) - coords = np.reshape(np.array(coords), [-1, natoms * 3]) + coords = np.reshape(np.array(coords), [nframes, natoms * 3]) if cells is None: pbc = False # make cells to work around the requirement of pbc diff --git a/deepmd/utils/batch_size.py b/deepmd/utils/batch_size.py index 41d9fd4f64..2b3117d849 100644 --- a/deepmd/utils/batch_size.py +++ b/deepmd/utils/batch_size.py @@ -100,10 +100,12 @@ def execute( OutOfMemoryError OOM when batch size is 1 """ + if natoms > 0: + batch_nframes = self.current_batch_size // natoms + else: + batch_nframes = self.current_batch_size try: - n_batch, result = callable( - max(self.current_batch_size // natoms, 1), start_index - ) + n_batch, result = callable(max(batch_nframes, 1), start_index) except OutOfMemoryError as e: # TODO: it's very slow to catch OOM error; I don't know what TF is doing here # but luckily we only need to catch once diff --git a/source/api_c/include/deepmd.hpp b/source/api_c/include/deepmd.hpp index 71ff5b3dcc..90c1c1c918 100644 --- a/source/api_c/include/deepmd.hpp +++ b/source/api_c/include/deepmd.hpp @@ -618,6 +618,7 @@ class DeepPot { * nframes x natoms x dim_aparam. * natoms x dim_aparam. Then all frames are assumed to be provided with the *same aparam. + * @warning Natoms should not be zero when computing multiple frames. **/ template void compute( @@ -630,7 +631,7 @@ class DeepPot { const std::vector &fparam = std::vector(), const std::vector &aparam = std::vector()) { unsigned int natoms = atype.size(); - unsigned int nframes = coord.size() / natoms / 3; + unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1; assert(nframes * natoms * 3 == coord.size()); if (!box.empty()) { assert(box.size() == nframes * 9); @@ -676,6 +677,7 @@ class DeepPot { * nframes x natoms x dim_aparam. * natoms x dim_aparam. Then all frames are assumed to be provided with the *same aparam. + * @warning Natoms should not be zero when computing multiple frames. **/ template void compute( @@ -690,7 +692,7 @@ class DeepPot { const std::vector &fparam = std::vector(), const std::vector &aparam = std::vector()) { unsigned int natoms = atype.size(); - unsigned int nframes = coord.size() / natoms / 3; + unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1; assert(nframes * natoms * 3 == coord.size()); if (!box.empty()) { assert(box.size() == nframes * 9); @@ -743,6 +745,7 @@ class DeepPot { * nframes x natoms x dim_aparam. * natoms x dim_aparam. Then all frames are assumed to be provided with the *same aparam. + * @warning Natoms should not be zero when computing multiple frames. **/ template void compute( @@ -758,7 +761,7 @@ class DeepPot { const std::vector &fparam = std::vector(), const std::vector &aparam = std::vector()) { unsigned int natoms = atype.size(); - unsigned int nframes = coord.size() / natoms / 3; + unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1; assert(nframes * natoms * 3 == coord.size()); if (!box.empty()) { assert(box.size() == nframes * 9); @@ -810,6 +813,7 @@ class DeepPot { * nframes x natoms x dim_aparam. * natoms x dim_aparam. Then all frames are assumed to be provided with the *same aparam. + * @warning Natoms should not be zero when computing multiple frames. **/ template void compute( @@ -827,7 +831,7 @@ class DeepPot { const std::vector &fparam = std::vector(), const std::vector &aparam = std::vector()) { unsigned int natoms = atype.size(); - unsigned int nframes = coord.size() / natoms / 3; + unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1; assert(nframes * natoms * 3 == coord.size()); if (!box.empty()) { assert(box.size() == nframes * 9); diff --git a/source/api_c/tests/test_deeppot_a_hpp.cc b/source/api_c/tests/test_deeppot_a_hpp.cc index a423e0acc6..814122d538 100644 --- a/source/api_c/tests/test_deeppot_a_hpp.cc +++ b/source/api_c/tests/test_deeppot_a_hpp.cc @@ -478,6 +478,23 @@ TYPED_TEST(TestInferDeepPotAHPP, cpu_lmp_nlist_type_sel) { } } +TYPED_TEST(TestInferDeepPotAHPP, cpu_build_nlist_empty_input) { + using VALUETYPE = TypeParam; + std::vector coord; + std::vector atype; + std::vector& box = this->box; + unsigned int natoms = 0; + deepmd::hpp::DeepPot& dp = this->dp; + double ener; + std::vector force, virial; + + dp.compute(ener, force, virial, coord, atype, box); + // no errors will be fine + EXPECT_EQ(force.size(), natoms * 3); + EXPECT_EQ(virial.size(), 9); + EXPECT_LT(fabs(ener), EPSILON); +} + TYPED_TEST(TestInferDeepPotAHPP, print_summary) { deepmd::hpp::DeepPot& dp = this->dp; dp.print_summary(""); diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index 785ed00cb8..23a0a7e663 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -574,7 +574,8 @@ void DeepPot::compute(ENERGYVTYPE& dener, const std::vector& fparam_, const std::vector& aparam_) { int nall = datype_.size(); - int nframes = dcoord_.size() / nall / 3; + // if nall==0, unclear nframes, but 1 is ok + int nframes = nall > 0 ? (dcoord_.size() / nall / 3) : 1; int nloc = nall; atommap = deepmd::AtomMap(datype_.begin(), datype_.begin() + nloc); assert(nloc == atommap.get_type().size()); @@ -658,7 +659,8 @@ void DeepPot::compute(ENERGYVTYPE& dener, const std::vector& fparam_, const std::vector& aparam__) { int nall = datype_.size(); - int nframes = dcoord_.size() / nall / 3; + // if nall==0, unclear nframes, but 1 is ok + int nframes = nall > 0 ? (dcoord_.size() / nall / 3) : 1; std::vector fparam; std::vector aparam_; validate_fparam_aparam(nframes, (aparam_nall ? nall : (nall - nghost)), @@ -753,7 +755,8 @@ void DeepPot::compute_inner(ENERGYVTYPE& dener, const std::vector& fparam, const std::vector& aparam) { int nall = datype_.size(); - int nframes = dcoord_.size() / nall / 3; + // if nall==0, unclear nframes, but 1 is ok + int nframes = nall > 0 ? (dcoord_.size() / nall / 3) : 1; int nloc = nall - nghost; std::vector> input_tensors; @@ -841,7 +844,8 @@ void DeepPot::compute(ENERGYVTYPE& dener, const std::vector& dbox, const std::vector& fparam_, const std::vector& aparam_) { - int nframes = dcoord_.size() / 3 / datype_.size(); + // if datype.size is 0, not clear nframes; but 1 is just ok + int nframes = datype_.size() > 0 ? (dcoord_.size() / 3 / datype_.size()) : 1; atommap = deepmd::AtomMap(datype_.begin(), datype_.end()); int nloc = datype_.size(); std::vector fparam; @@ -930,7 +934,8 @@ void DeepPot::compute(ENERGYVTYPE& dener, const std::vector& fparam_, const std::vector& aparam__) { int nall = datype_.size(); - int nframes = dcoord_.size() / 3 / nall; + // if nall==0, unclear nframes, but 1 is ok + int nframes = nall > 0 ? (dcoord_.size() / nall / 3) : 1; int nloc = nall - nghost; std::vector fparam; std::vector aparam_; diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index fad7e374ab..5994e9446f 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -380,7 +380,8 @@ int deepmd::session_input_tensors( const deepmd::AtomMap& atommap, const std::string scope, const bool aparam_nall) { - int nframes = dcoord_.size() / 3 / datype_.size(); + // if datype.size is 0, not clear nframes; but 1 is just ok + int nframes = datype_.size() > 0 ? (dcoord_.size() / 3 / datype_.size()) : 1; int nall = datype_.size(); int nloc = nall; assert(nall * 3 * nframes == dcoord_.size()); @@ -445,10 +446,13 @@ int deepmd::session_input_tensors( std::vector dcoord(dcoord_); atommap.forward(dcoord.begin(), dcoord_.begin(), 3, nframes, nall); std::vector aparam_(aparam__); - atommap.forward( - aparam_.begin(), aparam__.begin(), - aparam__.size() / nframes / (aparam_nall ? nall : nloc), nframes, - (aparam_nall ? nall : nloc)); + if ((aparam_nall ? nall : nloc) > 0) { + atommap.forward( + aparam_.begin(), aparam__.begin(), + aparam__.size() / nframes / (aparam_nall ? nall : nloc), nframes, + (aparam_nall ? nall : nloc)); + } + // if == 0, aparam__.size should also be 0, so no need to forward for (int ii = 0; ii < nframes; ++ii) { for (int jj = 0; jj < nall * 3; ++jj) { @@ -520,7 +524,8 @@ int deepmd::session_input_tensors( const int ago, const std::string scope, const bool aparam_nall) { - int nframes = dcoord_.size() / 3 / datype_.size(); + // if datype.size is 0, not clear nframes; but 1 is just ok + int nframes = datype_.size() > 0 ? (dcoord_.size() / 3 / datype_.size()) : 1; int nall = datype_.size(); int nloc = nall - nghost; assert(nall * 3 * nframes == dcoord_.size()); @@ -581,10 +586,13 @@ int deepmd::session_input_tensors( std::vector dcoord(dcoord_); atommap.forward(dcoord.begin(), dcoord_.begin(), 3, nframes, nall); std::vector aparam_(aparam__); - atommap.forward( - aparam_.begin(), aparam__.begin(), - aparam__.size() / nframes / (aparam_nall ? nall : nloc), nframes, - (aparam_nall ? nall : nloc)); + if ((aparam_nall ? nall : nloc) > 0) { + atommap.forward( + aparam_.begin(), aparam__.begin(), + aparam__.size() / nframes / (aparam_nall ? nall : nloc), nframes, + (aparam_nall ? nall : nloc)); + } + // if == 0, aparam__.size should also be 0, so no need to forward for (int ii = 0; ii < nframes; ++ii) { for (int jj = 0; jj < nall * 3; ++jj) { @@ -717,10 +725,13 @@ int deepmd::session_input_tensors_mixed_type( std::vector dcoord(dcoord_); atommap.forward(dcoord.begin(), dcoord_.begin(), 3, nframes, nall); std::vector aparam_(aparam__); - atommap.forward( - aparam_.begin(), aparam__.begin(), - aparam__.size() / nframes / (aparam_nall ? nall : nloc), nframes, - (aparam_nall ? nall : nloc)); + if ((aparam_nall ? nall : nloc) > 0) { + atommap.forward( + aparam_.begin(), aparam__.begin(), + aparam__.size() / nframes / (aparam_nall ? nall : nloc), nframes, + (aparam_nall ? nall : nloc)); + } + // if == 0, aparam__.size should also be 0, so no need to forward for (int ii = 0; ii < nframes; ++ii) { for (int jj = 0; jj < nall * 3; ++jj) { diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 0dc8a3743e..d0ff08032d 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -49,8 +49,8 @@ class MapAparamOp : public OpKernel { int nframes = aparam_tensor.shape().dim_size(0); int nloc = natoms(0); int nall = natoms(1); - int nnei = nlist_tensor.shape().dim_size(1) / nloc; - int numb_aparam = aparam_tensor.shape().dim_size(1) / nall; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; + int numb_aparam = nall > 0 ? aparam_tensor.shape().dim_size(1) / nall : 0; // check the sizes OP_REQUIRES(context, (nframes == nlist_tensor.shape().dim_size(0)), diff --git a/source/op/pairwise.cc b/source/op/pairwise.cc index d60bc3bccc..8ed140a14a 100644 --- a/source/op/pairwise.cc +++ b/source/op/pairwise.cc @@ -85,7 +85,7 @@ class PairwiseIdxOp : public OpKernel { nloc_qmmm.push_back(nloc_qmmm_ii); nghost_qm.push_back(nghost_qm_ii); nghost_qmmm.push_back(nghost_qmmm_ii); - nframes_qmmm.push_back(backward_qmmm_map.size() / nall); + nframes_qmmm.push_back(nall > 0 ? backward_qmmm_map.size() / nall : 0); } int max_nloc_qm = 1, max_nloc_qmmm = 1, max_nghost_qm = 0, max_nghost_qmmm = 0; diff --git a/source/op/prod_force.cc b/source/op/prod_force.cc index a2631b8c1d..d8ced591b9 100644 --- a/source/op/prod_force.cc +++ b/source/op/prod_force.cc @@ -58,8 +58,8 @@ class ProdForceOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); int nall = natoms(1); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), diff --git a/source/op/prod_force_grad.cc b/source/op/prod_force_grad.cc index fed8616534..2d14022279 100644 --- a/source/op/prod_force_grad.cc +++ b/source/op/prod_force_grad.cc @@ -65,8 +65,8 @@ class ProdForceGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_force_grad_multi_device.cc b/source/op/prod_force_grad_multi_device.cc index ffcd8f0b8b..bbcef6bd91 100644 --- a/source/op/prod_force_grad_multi_device.cc +++ b/source/op/prod_force_grad_multi_device.cc @@ -70,8 +70,8 @@ class ProdForceSeAGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), @@ -180,8 +180,8 @@ class ProdForceSeRGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_force_multi_device.cc b/source/op/prod_force_multi_device.cc index 935b5b9f2f..3eaf005f9a 100644 --- a/source/op/prod_force_multi_device.cc +++ b/source/op/prod_force_multi_device.cc @@ -89,8 +89,8 @@ class ProdForceSeAOp : public OpKernel { int nloc = natoms[0]; int nall = natoms[1]; int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument("number of samples should match")); @@ -187,8 +187,8 @@ class ProdForceSeROp : public OpKernel { int nloc = natoms[0]; int nall = natoms[1]; int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument("number of samples should match")); diff --git a/source/op/prod_force_se_a_grad.cc b/source/op/prod_force_se_a_grad.cc index 1c859158e0..21dd4fe00a 100644 --- a/source/op/prod_force_se_a_grad.cc +++ b/source/op/prod_force_se_a_grad.cc @@ -63,8 +63,8 @@ class ProdForceSeAGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_force_se_a_mask.cc b/source/op/prod_force_se_a_mask.cc index c2270f4234..32fcf54a79 100644 --- a/source/op/prod_force_se_a_mask.cc +++ b/source/op/prod_force_se_a_mask.cc @@ -49,7 +49,7 @@ class ProdForceSeAMaskOp : public OpKernel { int nloc = total_atom_num; int nall = total_atom_num; int ndescrpt = nall * 4; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), diff --git a/source/op/prod_force_se_a_mask_grad.cc b/source/op/prod_force_se_a_mask_grad.cc index 54eafecc19..6f841b1c7d 100644 --- a/source/op/prod_force_se_a_mask_grad.cc +++ b/source/op/prod_force_se_a_mask_grad.cc @@ -55,7 +55,7 @@ class ProdForceSeAMaskGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = total_atom_num; - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; int nnei = total_atom_num; // check the sizes diff --git a/source/op/prod_force_se_r_grad.cc b/source/op/prod_force_se_r_grad.cc index fbaf667675..f0b4b18323 100644 --- a/source/op/prod_force_se_r_grad.cc +++ b/source/op/prod_force_se_r_grad.cc @@ -57,8 +57,8 @@ class ProdForceSeRGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_virial.cc b/source/op/prod_virial.cc index dfac86b8cf..2719c6c670 100644 --- a/source/op/prod_virial.cc +++ b/source/op/prod_virial.cc @@ -63,8 +63,8 @@ class ProdVirialOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); int nall = natoms(1); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), diff --git a/source/op/prod_virial_grad.cc b/source/op/prod_virial_grad.cc index 2c179a2793..b06e273453 100644 --- a/source/op/prod_virial_grad.cc +++ b/source/op/prod_virial_grad.cc @@ -70,8 +70,8 @@ class ProdVirialGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_virial_grad_multi_device.cc b/source/op/prod_virial_grad_multi_device.cc index d3e7025e6e..215c26f184 100644 --- a/source/op/prod_virial_grad_multi_device.cc +++ b/source/op/prod_virial_grad_multi_device.cc @@ -76,8 +76,8 @@ class ProdVirialSeAGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), @@ -206,8 +206,8 @@ class ProdVirialSeRGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_virial_multi_device.cc b/source/op/prod_virial_multi_device.cc index 445770e85a..23b312b797 100644 --- a/source/op/prod_virial_multi_device.cc +++ b/source/op/prod_virial_multi_device.cc @@ -70,9 +70,9 @@ class ProdVirialSeAOp : public OpKernel { const int* natoms = natoms_tensor.flat().data(); int nloc = natoms[0]; int nall = natoms[1]; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument("number of samples should match")); @@ -169,9 +169,9 @@ class ProdVirialSeROp : public OpKernel { const int* natoms = natoms_tensor.flat().data(); int nloc = natoms[0]; int nall = natoms[1]; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument("number of samples should match")); diff --git a/source/op/prod_virial_se_a_grad.cc b/source/op/prod_virial_se_a_grad.cc index c914bfddaf..a22401d654 100644 --- a/source/op/prod_virial_se_a_grad.cc +++ b/source/op/prod_virial_se_a_grad.cc @@ -68,8 +68,8 @@ class ProdVirialSeAGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/prod_virial_se_r_grad.cc b/source/op/prod_virial_se_r_grad.cc index 90e6588b99..b874c828df 100644 --- a/source/op/prod_virial_se_r_grad.cc +++ b/source/op/prod_virial_se_r_grad.cc @@ -62,8 +62,8 @@ class ProdVirialSeRGradOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int nloc = natoms(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int ndescrpt = nloc > 0 ? net_deriv_tensor.shape().dim_size(1) / nloc : 0; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/soft_min_force.cc b/source/op/soft_min_force.cc index 7db6936025..a2970f4c3a 100644 --- a/source/op/soft_min_force.cc +++ b/source/op/soft_min_force.cc @@ -54,7 +54,7 @@ class SoftMinForceOp : public OpKernel { int nframes = du_tensor.shape().dim_size(0); int nloc = natoms(0); int nall = natoms(1); - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == sw_deriv_tensor.shape().dim_size(0)), diff --git a/source/op/soft_min_force_grad.cc b/source/op/soft_min_force_grad.cc index be53d74e26..752ad4f93d 100644 --- a/source/op/soft_min_force_grad.cc +++ b/source/op/soft_min_force_grad.cc @@ -62,7 +62,7 @@ class SoftMinForceGradOp : public OpKernel { int nframes = du_tensor.shape().dim_size(0); int nloc = natoms(0); - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/op/soft_min_virial.cc b/source/op/soft_min_virial.cc index a37940f651..91a94e01c3 100644 --- a/source/op/soft_min_virial.cc +++ b/source/op/soft_min_virial.cc @@ -60,7 +60,7 @@ class SoftMinVirialOp : public OpKernel { int nframes = du_tensor.shape().dim_size(0); int nloc = natoms(0); int nall = natoms(1); - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == sw_deriv_tensor.shape().dim_size(0)), diff --git a/source/op/soft_min_virial_grad.cc b/source/op/soft_min_virial_grad.cc index ef8f026f23..bc9cb96a63 100644 --- a/source/op/soft_min_virial_grad.cc +++ b/source/op/soft_min_virial_grad.cc @@ -67,7 +67,7 @@ class SoftMinVirialGradOp : public OpKernel { int nframes = du_tensor.shape().dim_size(0); int nloc = natoms(0); - int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nnei = nloc > 0 ? nlist_tensor.shape().dim_size(1) / nloc : 0; // check the sizes OP_REQUIRES(context, (nframes == grad_shape.dim_size(0)), diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index 006b391e49..12f677e618 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -13,6 +13,7 @@ from deepmd.env import ( GLOBAL_NP_FLOAT_PRECISION, MODEL_VERSION, + tf, ) from deepmd.infer import ( DeepPot, @@ -302,6 +303,23 @@ def test_2frame_atm(self): expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis=1) np.testing.assert_almost_equal(vv.ravel(), expected_sv.ravel(), default_places) + # TODO: needs to fix + @unittest.skipIf(tf.test.is_gpu_available(), reason="Segfault in GPUs") + def test_zero_input(self): + nframes = 1 + ee, ff, vv = self.dp.eval( + np.zeros([nframes, 0, 3]), self.box, np.zeros([0]), atomic=False + ) + # check shape of the returns + natoms = 0 + self.assertEqual(ee.shape, (nframes, 1)) + self.assertEqual(ff.shape, (nframes, natoms, 3)) + self.assertEqual(vv.shape, (nframes, 9)) + # check values + np.testing.assert_almost_equal(ff.ravel(), 0, default_places) + np.testing.assert_almost_equal(ee.ravel(), 0, default_places) + np.testing.assert_almost_equal(vv.ravel(), 0, default_places) + class TestDeepPotANoPBC(unittest.TestCase): @classmethod diff --git a/source/tests/test_deeppot_r.py b/source/tests/test_deeppot_r.py index c1746efa01..44c6e3c167 100644 --- a/source/tests/test_deeppot_r.py +++ b/source/tests/test_deeppot_r.py @@ -9,6 +9,7 @@ from deepmd.env import ( GLOBAL_NP_FLOAT_PRECISION, + tf, ) from deepmd.infer import ( DeepPot, @@ -430,6 +431,23 @@ def test_2frame_atm(self): expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis=1) np.testing.assert_almost_equal(vv.ravel(), expected_sv.ravel(), default_places) + # TODO: needs to fix + @unittest.skipIf(tf.test.is_gpu_available(), reason="Segfault in GPUs") + def test_zero_input(self): + nframes = 1 + ee, ff, vv = self.dp.eval( + np.zeros([nframes, 0, 3]), self.box, np.zeros([0]), atomic=False + ) + # check shape of the returns + natoms = 0 + self.assertEqual(ee.shape, (nframes, 1)) + self.assertEqual(ff.shape, (nframes, natoms, 3)) + self.assertEqual(vv.shape, (nframes, 9)) + # check values + np.testing.assert_almost_equal(ff.ravel(), 0, default_places) + np.testing.assert_almost_equal(ee.ravel(), 0, default_places) + np.testing.assert_almost_equal(vv.ravel(), 0, default_places) + class TestDeepPotRLargeBoxNoPBC(unittest.TestCase): @classmethod